Java API / Jersey put method - java

it's my first API in Java, so please, keep that in mind ;) I've got Controller.class where I'm keeping all my methods right now ( I will clean it later ;) ). As far as GET methods work perfectly I've got problem with PUT method when I want to create new user - it doesn't work. Any help please ? And advices cause - as I said - I'm newbie when it comes to API ;)
So this is my controller.class :
#Path("/api")
public class Controller {
List<Post> mBartoszPosts;
List<Post> mFelipePosts;
List<Post> mShawnPosts;
List<Post> mDavidPosts;
List<Post> mGraziellaPosts;
List<Post> mAllPosts;
List<User> mUsers;
User bartosz;
User felipe;
User shawn;
User david;
User graziella;
#Path("/user/{id}")
#GET
#Produces("application/json")
public Response getUser(#PathParam("id")int id) {
setUpUsers();
System.out.println("Liczba osob : " + mUsers.size());
for(User user : mUsers) {
if(id == user.getId()) {
String result = user.toString();
return Response.status(200).entity(user).build();
}
}
return null;
}
#Path("/post/{post_id}")
#GET
#Produces("application/json")
public Response getPost(#PathParam("post_id")int post_id) {
setUpUsers();
System.out.println("Liczba osob : " + mUsers.size());
for(Post post : mAllPosts) {
if(post_id == post.getId()) {
String result = post.toString();
return Response.status(200).entity(post).build();
}
}
return null;
}
#Path("/posts")
#GET
#Produces("application/json")
public Response getPosts() {
setUpUsers();
String response = new Gson().toJson(mAllPosts );
return Response.status(200).entity(response).build();
}
#PUT
#Path("user/new/{id}/{post}")
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public Response updateEmployeeById(#PathParam("id") Integer id,#PathParam("post") String userPost)
{
List<Post>userPosts = new ArrayList();
Post post = new Post(99,userPost,"Bartosz");
userPosts.add(post);
User updatedEmployee = new User(id,"Bartek","Szlapa",userPosts);
if(updatedEmployee.getName() == null) {
return Response.status(400).entity("Please provide the employee name !!").build();
}
updatedEmployee.setId(id);
updatedEmployee.setName(updatedEmployee.getName());
System.out.println(updatedEmployee.getName());
return Response.ok().entity(updatedEmployee).build();
}
public int maxValue(int array[]){
int max = Arrays.stream(array).max().getAsInt();
return max;
}
}
As you see the last method is PUT and it doesn't work: Here is my test client :
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Client client = ClientBuilder.newClient( new ClientConfig().register( Controller.class ) );
WebTarget webTarget = client.target("http://localhost:8080/JerseyDemos/rest").path("api").path("user").path("new").path("77");
List<Post>userPosts = new ArrayList();
Post post = new Post(99,"Bartek Szlapa","Testing post ...");
userPosts.add(post);
User emp = new User(99,"Bartek","Szlapa",userPosts);
Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_XML);
Response response = invocationBuilder.put(Entity.entity(emp, MediaType.APPLICATION_XML));
User user = response.readEntity(User.class);
System.out.println(response.getStatus());
System.out.println(user);
}
}
And finally my error :
Exception in thread "main" org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=application/xml, type=class entities.User, genericType=class entities.User.
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:248)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:163)
at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1135)
at org.glassfish.jersey.client.ClientRequest.doWriteEntity(ClientRequest.java:516)
at org.glassfish.jersey.client.ClientRequest.writeEntity(ClientRequest.java:498)
at org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:384)
at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:282)
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:278)
at org.glassfish.jersey.client.JerseyInvocation.lambda$invoke$0(JerseyInvocation.java:753)
at org.glassfish.jersey.internal.Errors.process(Errors.java:316)
at org.glassfish.jersey.internal.Errors.process(Errors.java:298)
at org.glassfish.jersey.internal.Errors.process(Errors.java:229)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:414)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:752)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:445)
at org.glassfish.jersey.client.JerseyInvocation$Builder.put(JerseyInvocation.java:334)
at test.Test.main(Test.java:33)
Thanks in advance for help!

It seems 2 problems in your client code -
For removing this error, you should add jersey-media-jaxb JAR in your classpath. If you are using maven, add below dependency in your pom.xml -
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-jaxb</artifactId>
<version>${jersey.version}</version>
</dependency>
As per your PUT method API specification -
public Response updateEmployeeById(#PathParam("id") Integer id,#PathParam("post") String userPost) {
Your REST service needs only path parameter id and post. No other input is required. However, in your client code, you are sending User class object emp object while calling your API -
Response response = invocationBuilder.put(Entity.entity(emp, MediaType.APPLICATION_XML));
Since you are not receiving this emp object in your API, so this data will get lost. So, either you should update your API for accepting User class object in request or don't sent this object from your client code.

Related

Passing a BODY of a POST request to the server

I have built a Restful-API Java(SpringBoot) and created the needed requests.
The following request is a POST Request to add new Category.
I have tested the POST request by POSTMAN, and it working as expected.
I am building the client-side in ASP.NET 5.x.x.
Now the problem appear when I am calling the post request, it seems the API doesn't receive the data (#RequestBody category) that has been send from the client.
Here is a code simple of how I have created them
Server Side:
#ResponseStatus(HttpStatus.CREATED)
#PostMapping(value = "/add", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public CategoryDTO create(#RequestBody CategoryDTO category) {
log.info("Adding new Category Name: " + category.getName());
return categoryMapper.asCategoryDTO(categoryService.save(categoryMapper.asCategory(category)));
}
Client Side
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Category category)
{
Category newCategory = new Category();
// Serialize the concrete class into a JSON String
var stringPayload = JsonConvert.SerializeObject(category);
// Wrap the JSON inside a StringContent which then can be used by the HttpClient class
StringContent content = new StringContent(stringPayload);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.PostAsync("http://localhost:8080/category/add", content))
{
string apiResponse = await response.Content.ReadAsStringAsync();
newCategory = JsonConvert.DeserializeObject<Category>(apiResponse);
}
}
return RedirectToAction("Index");
}
I don't know what is wrong there, could anybody help!
EDIT--
Here is the request via postman
EDIT
I have created another POST request but as a RequestParam instead of RequestBody
#ResponseStatus(HttpStatus.CREATED)
#PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
public CategoryDTO addCategory(#RequestParam(name = "categoryName") String categoryName){
return categoryMapper.asCategoryDTO(categoryService.addCategory(categoryName));
}
and created in the client side the request as following
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Category category)
{
Category newCategory = new Category();
var parameters = new Dictionary<string, string> { { "categoryName", category.Name } };
var encodedContent = new FormUrlEncodedContent(parameters);
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.PostAsync("http://localhost:8080/category/add", encodedContent))
{
string apiResponse = await response.Content.ReadAsStringAsync();
newCategory = JsonConvert.DeserializeObject<Category>(apiResponse);
}
}
return RedirectToAction("Index");
}
And It's works fine!
So the problem is how to pass the data via the httpClient, which need to be of type RequestBody (the data in the body not in the header!) also as a application/json.
So how to pass the data?
I suppose that your spring boot application just blocks POST request because you didn't provide instruction how to handle requests. Try to disable csrf protection like it did here: https://stackoverflow.com/a/48935484/13314717
It might be a problem in the naming convention. Starting with capital letters in properties in C#, and starting with lowercase in Java.
If your class looks like this in C#
class Category {
int Id;
string Name;
...
}
And like this in Java
class Category {
int id;
string name;
...
}
It is not going to work so you have to match the property names. So make either both id or both Id.

Tomcat Server quits working when GET and POST added to it

for a project I have to make a Java backend using RESTful services, restservices. When I add a certain resource to my project with a get method and a post method, the server gives a 500 error. When i remove the GET and POST methods, it works fine again. Can anyone explain why it won't work?
Resource file:
package nl.hu.v1ipass.testipass.webservices;
#Path("/aanmeldingen")
public class AanmeldingResource {
private JsonObjectBuilder aanmeldingToJson(Aanmelding aanmelding) {
JsonObjectBuilder job = Json.createObjectBuilder();
job.add("lidnummer", aanmelding.getEter().getLidNummer());
job.add("lidnaam", aanmelding.getEter().getName());
job.add("gerechtnaam", aanmelding.getGerecht().getName());
return job;
}
#GET
#RolesAllowed("admin")
#Produces("appplication/json")
public String getAanmeldingen(#FormParam("datum") String datum) {
AanmeldingService service = new AanmeldingService();
JsonArrayBuilder jab = Json.createArrayBuilder();
for (Aanmelding a : service.getAanmeldingDate(datum)){
jab.add(aanmeldingToJson(a));
}
JsonArray array = jab.build();
return array.toString();
}
#POST
#RolesAllowed({"user", "admin"})
public Response addAanmelding(#FormParam("datum") String datum, #FormParam("gerecht") int gerechtId, #FormParam("lidnummer") int lidnummer) throws SQLException {
AanmeldingService service = ServiceProvider.getAanmeldingService();
if(service.getAanmeldingDate(datum) == null) {
Aanmelding returnAanmelding = service.addAanmelding(lidnummer, gerechtId);
String a = aanmeldingToJson(returnAanmelding).build().toString();
return Response.ok(a).build();
} else {
return Response.status(Response.Status.FOUND).build();
}
}
}
UPDATE: with only the POST method, the server works fine. So what goes wrong in my GET method?
Try changing
#Produces("appplication/json")
to
#Produces("application/json")
notice the spelling mistake

Change URL pattern of rest API

#Path("/ftocservice")
public class RestService {
#Path("{f}")
#GET
#Produces("application/json")
public Response convertFtoCfromInput(#PathParam("f") float f)
throws Exception {
DbCon db = new DbCon();
ArrayList<Student> students = db.getStudentList();
JSONArray jsonArray = new JSONArray(students);
String result = jsonArray.toString();
return Response.status(200).entity(result).build();
}
}
I'm using above source code to generate rest API and user is requesting through the API as follows.
http://localhost:8080/RestExample/RestService/ftocservice/23
I need to change the request URL as follows.
http://localhost:8080/RestExample/RestService/ftocservice?f=23
Please help to change the source code to change request URL as given. Thanks
Change to use #QueryParam instead:
#Path("/ftocservice")
public class RestService {
#GET
#Produces("application/json")
public Response convertFtoCfromInput(#QueryParam("f") float f)
throws Exception {
DbCon db = new DbCon();
ArrayList<Student> students = db.getStudentList();
JSONArray jsonArray = new JSONArray(students);
String result = jsonArray.toString();
return Response.status(200).entity(result).build();
}
}
See this link for more info on parameter types in JAX-RS.
This tutorial by Mkyong.com is also quite nice.
use #QueryParam instead of #PathParam

How to get array from Http Post in a Restful Web Service?

I have a controller for AngularJS Framework. I use a Http Post Request to send an array to a server. How to get this array in a java method?
This is my controller
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
var indici = new Array();
indici.push(1);
indici.push(2);
$http.post("http://localhost:8080/SistemiDistribuiti/rest/Point/Trovati", indici, {
headers: { 'Content-Type': 'application/json' }
}).success(function(receivedData, status) {
$scope.someData = receivedData;
});
And this is my java class but i don't know how to get my array.
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.POST;
import javax.ws.rs.Consumes;
#Path("Point")
public class PointService {
#POST
#Path("Trovati")
#Consumes(MediaType.APPLICATION_JSON)
public void RetrieveData() {
//how print my array?
}
You have to use #GET as below:
#GET
#Path("/blabla")
public Response receiveListOfStrings(#QueryParam("list") final List<String> list){
log.info("receieved list of size="+list.size());
return Response.ok().build();
}
And request:
GET http://example.com/services/echo?list=balbla&list=asdasd&list=BYE
Post doesn't support this. Or you can use #PUT with complex type.
Put example:
#PUT
public Response putExample(MyObject obj) {
log.info("receieved list of size="+obj.getList().size());
return Response.ok().build();
}
In this put example you can see I used a custom MyObject Here's its codes:
public class MyObject{
private List<String> list = new ArrayList<String>();
public List<String> getList(){
return list;
}
public void setList( List<String> list ){
this.list = list;
}
#Override
public String toString(){
return "MyObject [list=" + list + "]";
}
}
As you can see there's a list property in your MyObject class. So you can print anything by calling getList as my example above.
I agree with #lex82, you don't send the payload within your request. See the documentation for $http.post: https://docs.angularjs.org/api/ng/service/$http#post. Be sure to understand what promises are and how they are used within the HTTP support of Angular.
Here is a sample:
var dataToSend = {
// some JSON data
};
$http.post("/some-url", dataToSend, {
headers: { 'Content-Type': 'application/json' }
}).success(function(receivedData, status) {
$scope.someData = receivedData;
});
That said, you say that you don't receive the data on the server. The first to do is to check your raw request. This can be done within Chrome using the Chrome Developer Tools (CRTL + SHIFT + i). This will give you access to a Network tab containing every request. Click on the request corresponding to your AJAX request and check if there is a payload in your request. If so, it's a problem on your server side within your JAXRS application.
Do you some exceptions within your JAXRS application?
Hope it helps you,
Thierry
Apache has an http library that can be used to make various http requests.
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.2</version>
</dependency>
You will also need a library that can be used to transform your json objects into Java object. Google has created a library called gson that I will use in my example.
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.4</version>
</dependency>
You are also going to have to create a Java object that represents your data. This will be used to map your json object to a java object or "pojo". I'm not sure what your JSON objects look like, but I'm going to use a generic example called Response.
public class Response
{
private List<Example> examples;
private double total;
private String someString;
public QuoteResponse()
{
super();
}
public List<Examples> getExamples() {
return examples;
}
public void setExamples(List<Examples> examples)
{
this.examples = examples;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public String getSomeString() {
return someString;
}
public void setPrint_type(String someString) {
this.someString = someString;
}
}
Your java object has to have the same number of fields with the same type and same name as your JSON object.
Next, you will have to write a function that calls your angular api. See an example below:
public Response getJsonData()
{
params = new Params();
String url = "https://www.yoururl.com/controller/function_you_want;
Response response = null;
HttpGet httpGet = new HttpGet(url);
try
{
response = httpClient.execute(httpGet);
//check to make sure that everything is ok
if(response.getStatusLine().getStatusCode() == 200)
{
entity = response.getEntity();
jsonResponse = EntityUtils.toString(entity);
JsonNode root = mapper.readTree(jsonResponse).get("result");
response = gson.fromJson(root.toString(),Response.class);
}
}
catch (IOException e)
{
e.printStackTrace();
}
return response;
}
That's about it. Let me know if you have any questions.

Generic method, RESTful app

I'm using RESTful application in my java project. Normally in my unit test classes, I use methods like this:
public Employee getEmployeeByEmail(String email) {
ClientResponse clientResponse = webResource.path(beginPath + "getByEmail/" + email).get(
ClientResponse.class);
Employee employee = null;
if (200 == clientResponse.getStatus()) {
employee = clientResponse.getEntity(Employee.class);
}
return employee;
}
... but I have to use similar methods in almost 12 different classes. This is what I decided to do:
public class TestManager<T> {
private WebResource webResource;
private String beginPath;
private Class<T> clazz;
public TestManager(WebResource webResource, String beginPath, Class<T> clazz) {
this.webResource = webResource;
this.beginPath = beginPath;
this.clazz = clazz;
}
public boolean objectExists(String methodPath, String uniqueFieldName, String uniqueField) {
boolean check = false;
ClientResponse clientResponse = webResource.path(beginPath + methodPath + "/" + uniqueField).get(
ClientResponse.class);
JSONObject jsonObject = clientResponse.getEntity(JSONObject.class);
if (200 == clientResponse.getStatus() && !jsonObject.isNull(uniqueFieldName)) {
check = true;
}
return check;
}
public T getObjectById(String methodPath, long id) {
ClientResponse clientResponse = webResource.path(beginPath + methodPath + "/" + id).get(
ClientResponse.class);
T object = null;
if (200 == clientResponse.getStatus() && !clientResponse.getEntity(JSONObject.class).isNull("id")) {
object = clientResponse.getEntity(clazz);
}
return object;
}
}
The method objectExists() works fine, but getObjectById() method generate stack trace:
javax.ws.rs.WebApplicationException: javax.xml.bind.UnmarshalException: Error creating JSON-based XMLStreamReader - with linked exception:[javax.xml.stream.XMLStreamException: java.io.IOException: stream is closed]
It seems that I can't do this:
object = clientResponse.getEntity(clazz);
But I have no idea how to fix it. Sorry for my english :P
Edit:
Im using jersey
Edit2:
Solution:
The problem was I used getEntity() method twice ... If I use it only once ... it works ... damn it
It is a GET call. try calling it from a browser.
If that gives the same error, then there is nothing wrong with your client.
If you're having issues just with unit testing, then you might want to take a look at the Jersey Test Framework. Here's a link to the jersey docs on it, google can point you to further tutorials.

Categories

Resources