I'm using Spring FeignClient to access a RESTful endpoint, the endpoint returns an xml,
I want to get the response as a JSON, which in turn will map to a POJO.
1) When I access the endpoint on the browser, I get response as below,
<ns3:Products xmlns:ns2="http://schemas.com/rest/core/v1" xmlns:ns3="http://schemas/prod/v1">
<ProductDetails>
<ProdId>1234</ProdId>
<ProdName>Some Text</ProdName>
</ProductDetails>
</ns3:Products>
2) #FeignClient(value = "productApi", url = "http://prodservice/resources/prod/v1")
public interface ProductApi {
#GetMapping(value="/products/{productId}", produces = "application/json")
ProductDetails getProductDetails(#PathVariable("productId") String productId)
// where, /products/{productId} refers the RESTful endpoint
// by mentioning, produces = "application/json", I believe the response xml would be converted to JSON Java POJO.
3) POJO
public class ProductDetails {
private String ProdId;
private String ProdName;
//...setters & getters
}
4) Service Layer
ProductDetails details = productApi.getProductDetails(productId);
In the 'details' object, both ProdId & ProdName are coming as null.
Am I missing anything here? Firstly, Is it possible to get response as JSON instead of XML?
If that RESTful service is programmed to return only xml-response, then you cannot ask it to give you json-based response.
But in your case the problem is with class where you want to map the result.
This xml response actually wraps ProductDetails tag into ns3:Products.
So you need to create another class which will hold a reference to ProductDetails object:
public class Product { //class name can be anything
private ProductDetails ProductDetails;
//getters, setters
}
Then change the type of getProductDetails method to Product.
If you still get nulls in your response, then it's probably because of ObjectMapper configuration. But you can always add #JsonProperty annotation for your fields (in
this case it would be #JsonProperty("ProductDetails") for ProductDetails field in Product, and #JsonProperty("ProdId") and #JsonProperty("ProdName") for fields in ProductDetails).
Related
Let's say I have:
#GET
public UserList fetch(#PathParam("user") String userId) {
// Do stuff here
}
Now, let's say I have my own type for userId, let's call it UserId. Is it possible to parse that String to UserId when it is passed into the fetch method, i.e.:
#GET
public UserList fetch(#PathParam("user") UserId userId) {
// Do stuff here
}
I realize I can parse the String once I am inside the method, but it would be more convenient that my method gets the type I want.
Well you've attempted to make a GET call with a request body is what I find not very helpful. Do read Paul's answer here -
you can send a body with GET, and no, it is never useful to do so
What would be good to practice is, to make a PUT or a POST call (PUT vs POST in REST) as follows -
#POST
#Path("/some-path/{some-query-param}")
public Response getDocuments(#ApiParam("user") UserId userId,
#PathParam("some-query-param") String queryParam) {
UserId userIdInstance = userId; // you can use the request body further
Note - The ApiParam annotation used is imported from the com.wordnik.swagger.annotations package. You can similarily use FormParam,QueryParam according to your source of input.
Dropwizard is using Jersey for HTTP<->Java POJO marshalling. You could use the various annotations from Jersey #*Param (#FormParam, #QueryParam, etc.) for some of the parameters.
If you need to use map/marshall to/from Java POJOs take a look at the test cases in Dropwizard:
#Path("/valid/")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class ValidatingResource {
#POST
#Path("foo")
#Valid
public ValidRepresentation blah(#NotNull #Valid ValidRepresentation representation, #QueryParam("somethingelse") String xer) {
return new ValidRepresentation();
}
This defines an API endpoint responding to HTTP POST method which expects ValidRepresentation object and "somethingelse" as HTTP method query parameter. The endpoint WILL respond ONLY when supplied with JSON parameters and will return only JSON objects (#Produces and #Consumes on the class level). The #NotNull requires that object to be mandatory for the call to succeed and #Valid instructs Dropwizard to call Hibernate validator to validate the object before calling the endpoint.
The ValidRepresentation class is here:
package io.dropwizard.jersey.validation;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;
public class ValidRepresentation {
#NotEmpty
private String name;
#JsonProperty
public String getName() {
return name;
}
#JsonProperty
public void setName(String name) {
this.name = name;
}
}
The POJO is using Jackson annotations to define how JSON representation of this object should look like. #NotEmtpy is annotation from Hibernate validator.
Dropwizard, Jersey and Jackson take care of the details. So for the basic stuff this is all that you need.
I have a java web maven project with JAX-RS using resteasy version 2.2.1.GA implementation. All JAX-RS resources on the project produces y consumes application/json. My problem is that when I returning a single POJO, even an array of this, only serialize the values of the attributes.
Example:
Given the following classes:
public class Pojo {
private Integer attr1;
private String attr2;
// GETTERs and SETTERs
}
#Path("pojos")
#Consumes("application/json")
#Produces("application/json")
public class PojoResource {
#GET
public Response list() {
List<Pojo> listResult = new ArrayList<>();
Pojo pojo = new Pojo();
pojo.setAttr1(1);
pojo.setAttr2("asdf");
listResult.add(pojo);
return Response.ok().entity(listResult).build();
}
}
If I do a GET request to /pojos, the result for the example above is [[1, "asdf"]], instead of [{"attr1":1,"attr2":"asdf"}]
I don't know if a need to write a specific Provider. My project configuration is similar to this.
I realized my mistake is that data recovery in layer model is as a vector of objects and return that without processing (create a POJO that represent the data).
A Rest service is mapped on one url with some #RequestBody where i am mapping json to pojo. Pojo contains nested classes following is sample code.
#RequestMapping(value = "/saveExampleObject.html", method = RequestMethod.POST)
public #ResponseBody List<String> saveExampleObjectDefintion(#RequestBody ExampleObject exampleObject) throws DataAccessException,DataNotPersistException {
List<String> msg = saveService.save(exampleObject);
return msg;
}
and the object is like
class ExampleObject{
String name;
SubClass subClass;
.....
}
and json is
{
"name":"name",
"subClass":{
.....
}
I have configured spring mvc annotation and conversion is also happening.
But some fields are null. I cross checked names of null field they are same as in json and pojo.
P.S. Only first fields are getting values in subclass.Thanks.
in your json you have subClass but in your class you have subclass... is case sensitive
Here the setters were not defined properly and hence there was an error. Spring MVC uses the setters to properly convert POJO to JSON and vice versa.
I'm using RoboSpice with Spring Android to perform REST api calls.
Data need to be sent with the Content-Type set to application/x-www-form-urlencoded.
Let's say I have a Pojo class like this:
public class Pojo {
private String pojoAttribute;
// getter + setter
}
Here is my request class:
public class PojoRequest extends AbstractApiRequest<PojoResult> {
private Pojo pojo;
public PojoRequest(Pojo pojo) {
super(PojoResult.class);
this.pojo = pojo;
}
#Override
public PojoResult loadDataFromNetwork() throws Exception {
HttpEntity<Pojo> requestEntity = new HttpEntity<Pojo>(pojo, getDefaultHeaders());
String url = buildUrlForPath("mypath");
RestTemplate restTemplate = getRestTemplate();
restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
return restTemplate.postForObject(url, requestEntity, PojoResult.class);
}
}
So, suppose I need to send this body:
pojo_attribute=foo
Now my code does not work because FormHttpMessageConverter does not handle POJOs.
What I would like to be able to do is something like this:
public class Pojo {
#FormProperty("pojo_attribute")
private String pojoAttribute;
// getter + setter
}
With a magic HttpMessageConverter that converts my POJO into key=value format taking care of converting the pojoAttribute to pojo_attribute by inspecting the #FormProperty (does not exist) annotation the same way Jackson does with #JsonProperty.
My questions are:
- is it possible to do this with existing classes/annotations?
- is there another way to do something similar?
- would it be overkill if I create my own HttpMessageConverter and set of annotations to do just that?
For this example, the user wishes to create a blog post for their site. Form submission is handled through AJAX. The POST request is handled by the createPost method in the controller. The method extracts the json data and combines it with the users session data to construct the appropriate Post object. It then validates the data and returns an appropriate response.
The Post model is as follows:
#Entity
public Post extends model {
#Id
public Long id;
#Required
public User author;
#Required
public String title;
#Required
public String body;
}
The controller method is as follows:
#BodyParser.Of(BodyParser.Json.class)
public static Result createPost() {
JsonNode json = request().body().asJson();
Post post = new Post();
post.author = User.findbyId(request().username());
post.title = json.findPath("title").textValue();
post.body = json.findPath("body").textValue();
Form<Post> filledForm = Form.form(Post.class).bind(Json.toJson(post));
if (filledForm.hasErrors())
return badRequest(filledForm.errorsAsJson());
// save post
return ok();
}
Now, this method works, however, there must be a better way of doing it rather than taking the json request, extracting it into an object and then converting that object back into json so that it can be bound to the form. Any ideas?
The common way to do it is using bindFromRequest in the controller side.
public static Result savePost() {
Form<Post> postForm= form(Post .class).bindFromRequest();
if(postForm.hasErrors()) {
Logger.error("Form has errors: " + postForm.errorsAsJson());
return badRequest(filledForm.render(postForm));
}
Post post=postForm.get();
post.save()
....
}
For a full example you can checkout the forms sample.
And the AJAX post could be something like that:
function postUrl(form){
var postData = new FormData($(form)[0])
var formURL = $(form).attr("action");
var request=$.ajax({
url : formURL, type: "POST", data : $(form).serialize(),
});
request.done(function(data) {
//Whatever
});
}
It's a commonly discussed issue in Play that form classes shouldn't really be domain classes. Only works in simple cases.
One alternative is to create a form-data class and bind that. The form-data class can contain data from many different models. Then have code that loads your domain object (Post) a copy fields from form-data object. I use code-generation for the form-data to domain-object code. YMMV.