I intended to bind a JSON string to POJO annotated with GSON, the JSON response is from the ReSTFUL service to list all countries: http://services.groupkt.com/country/get/all
the response is fine, which looks like
{
"RestResponse": {
"messages": [
"More webservices are available at http://www.groupkt.com/post/f2129b88/services.htm",
"Total [249] records found."
],
"result": [
{
"name": "Afghanistan",
"alpha2_code": "AF",
"alpha3_code": "AFG"
},
{
"name": "Åland Islands",
"alpha2_code": "AX",
"alpha3_code": "ALA"
},
...
]
}
}
The POJO Country and its associated classes were created using this tool:http://www.jsonschema2pojo.org/ and they look like:
Country.java
public class Country implements Serializable{
#SerializedName("RestResponse")
#Expose
private RestResponse restResponse;
public RestResponse getRestResponse() {
return restResponse;
}
public void setRestResponse(RestResponse restResponse) {
this.restResponse = restResponse;
}
}
RestResponse.java
public class RestResponse implements Serializable{
#SerializedName("messages")
#Expose
private List<String> messages = null;
#SerializedName("result")
#Expose
private List<Result> result = null;
public List<String> getMessages() {
return messages;
}
public void setMessages(List<String> messages) {
this.messages = messages;
}
public List<Result> getResult() {
return result;
}
public void setResult(List<Result> result) {
this.result = result;
}
}
Result.java
public class Result implements Serializable{
#SerializedName("name")
#Expose
private String name;
#SerializedName("alpha2_code")
#Expose
private String alpha2Code;
#SerializedName("alpha3_code")
#Expose
private String alpha3Code;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAlpha2Code() {
return alpha2Code;
}
public void setAlpha2Code(String alpha2Code) {
this.alpha2Code = alpha2Code;
}
public String getAlpha3Code() {
return alpha3Code;
}
public void setAlpha3Code(String alpha3Code) {
this.alpha3Code = alpha3Code;
}
}
The code below however failed to bind the JSON string to the GSON annotated POJOs - the restResponse is NULL, so are the message and result. Can anyone tell me what went wrong?
#SpringBootApplication
public class App implements CommandLineRunner
{
private static Logger log = LoggerFactory.getLogger(App.class);
/*
* boiler plate code
* */
public static void main( String[] args )
{
SpringApplication.run(App.class, args);
}
/*
* Configuration section
* */
#Bean
public RestTemplate newRestTemplate(){
RestTemplate rt = new RestTemplate();
return rt;
}
/*
* public APIs section
* */
#Autowired
private RestTemplate restTemplate;
#Override
public void run(String... args) throws Exception {
String url = "http://services.groupkt.com/country/get/all";
ResponseEntity<String> res = restTemplate.getForEntity(url, String.class);
log.info("{}",res.getBody());
GsonHttpMessageConverter msgConverter = new GsonHttpMessageConverter();
Gson gson = new GsonBuilder().setPrettyPrinting().create();
msgConverter.setGson(gson);
restTemplate.getMessageConverters().add(msgConverter);
Country country = restTemplate.getForObject(url, Country.class);
RestResponse resp = country.getRestResponse();
List<Result> l = resp.getResult();
for(Result r : l){
log.info("country name = {}",r.getName());
}
}
}
I managed to update the code like below and it works now:
RestTemplate rt = new RestTemplate();
String url = "http://services.groupkt.com/country/get/all";
ResponseEntity<String> resp = rt.getForEntity(url, String.class);
assertEquals(resp.getStatusCode(), HttpStatus.OK);
Gson gson = new GsonBuilder().create();
Country c = gson.fromJson(resp.getBody(), Country.class);
still don't know why the code below didn't work, though.
Country country = restTemplate.getForObject(url, Country.class);
Related
I am new to Spring boot, and was trying to create a post api to post the following json to.
However, when I do a get on the api, for the nested elements, null values are displayed.
Json Request:
{
"messageType": "abcd",
"messageVersion": "1.1.0",
"p_messageVersion": "1.095",
"acsTransID": "6834628",
"p_formValues_BRW": {
"action": "http://10.10.65.96:8080/CORE/Test.htm",
"correctFormData": "1234",
"incorrectFormData": "0000",
"cancelFormData": "true"
}
}
Response on Doing a Get:
[{"acsTransID":"6834628","p_messageVersion":"1.095","messageVersion":"1.1.0","messageType":"abcd","p_formValues_BRW":{"action":null,"correctFormData":null,"incorrectFormData":null,"cancelFormData":null}}]
My Model Object
public class Product {
#JsonProperty("acsTransID")
private String acsTransID;
#JsonProperty("p_messageVersion")
private String p_messageVersion;
#JsonProperty("messageVersion")
private String messageVersion;
#JsonProperty("messageType")
private String messageType;
#JsonProperty("p_formValues_BRW")
private p_formValues_BRW p_formValues_BRW;
public Product(p_formValues_BRW p_formValues_BRW) {
this.p_formValues_BRW=p_formValues_BRW;
}
public Product() {
}
public String getacsTransID() {
return acsTransID;
}
public void setacsTransID(String acsTransID) {
this.acsTransID = acsTransID;
}
public String getp_messageVersion() {
return p_messageVersion;
}
public void setp_messageVersion(String p_messageVersion) {
this.p_messageVersion = p_messageVersion;
}
public String getmessageVersion() {
return messageVersion;
}
public void setmessageVersion(String messageVersion) {
this.messageVersion = messageVersion;
}
public String getmessageType() {
return messageType;
}
public void setmessageType(String messageType) {
this.messageType = messageType;
}
public p_formValues_BRW getp_formValues_BRW() {
return p_formValues_BRW;
}
public void setp_formValues_BRW(p_formValues_BRW p_formValues_BRW) {
this.p_formValues_BRW = p_formValues_BRW;
}
/*
public Product withPFormValuesBRW(PFormValuesBRW pFormValuesBRW) {
this.pFormValuesBRW = pFormValuesBRW;
return this;
}*/
}
class p_formValues_BRW {
#JsonProperty("action")
private String action;
#JsonProperty("correctFormData")
private String correctFormData;
#JsonProperty("incorrectFormData")
private String incorrectFormData;
#JsonProperty("cancelFormData")
private String cancelFormData;
public String getaction() {
return action;
}
public void setaction(String action) {
this.action = action;
}
public String getcorrectFormData() {
return correctFormData;
}
public void setcorrectFormData(String correctFormData) {
this.correctFormData = correctFormData;
}
public String getincorrectFormData() {
return incorrectFormData;
}
public void setincorrectFormData(String incorrectFormData) {
this.incorrectFormData = incorrectFormData;
}
public String getcancelFormData() {
return cancelFormData;
}
public void setcancelFormData(String cancelFormData) {
this.cancelFormData = cancelFormData;
}
}
My Controller
#RestController
public class ProductServiceController {
private static Map<String, Product> productRepo = new HashMap<>();
#RequestMapping(value = "/products", method = RequestMethod.POST)
public ResponseEntity<Object> createProduct(#RequestBody Product product, p_formValues_BRW p_formValues_BRW) {
product.setp_formValues_BRW(p_formValues_BRW);
productRepo.put(product.getacsTransID(), product);
// productRepo.put(product., PFormValuesBRWRepo);
return new ResponseEntity<>("Product is created successfully", HttpStatus.CREATED);
}
#RequestMapping(value = "/products")
public ResponseEntity<Object> getProduct() {
return new ResponseEntity<>(productRepo.values(), HttpStatus.OK);
}
}
What I am doing wrong. Also, would it be better to use JPARepositories and #autowired.
You don't need to add p_formValues_BRW in createProduct() function's parameter separately, because on your JSON Request you pass p_formValues_BRW as nested object.
So on your controller when you hit "/products" you will get p_formValues_BRW in Product, so function after changes look like this:
#RequestMapping(value = "/products", method = RequestMethod.POST)
public ResponseEntity<Object> createProduct(#RequestBody Product product) {
product.setp_formValues_BRW(product.getp_formValues_BRW());
productRepo.put(product.getacsTransID(), product);
// productRepo.put(product., PFormValuesBRWRepo);
return new ResponseEntity<>("Product is created successfully", HttpStatus.CREATED);
}
As you already giving p_formValues_BRW in request body, you need not add it in Product.
#RequestMapping(value = "/products", method = RequestMethod.POST)
public ResponseEntity<Object> createProduct(#RequestBody Product product) {
productRepo.put(product.getacsTransID(), product);
// productRepo.put(product., PFormValuesBRWRepo);
return new ResponseEntity<>("Product is created successfully", HttpStatus.CREATED);
}
I have the APIResponse class which extends the Object class like <T extends Object> but while getting the response body from the rest template getting the data into the Object class, not to the Book class.
If I try to fetch the data into the Book class it gives the null.
I have tried typecasting the response in The Book Object but no success.
ex.ApiResponse<Book>.
public void testCreate(){
ClientHttpRequestFactory factory = new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory());
RestTemplate restTemplate = new RestTemplate(factory);
BookDto bookDto = new BookDto("Pranav","dummy","dummy");
String url = "http://localhost:9090/books";
HttpEntity<BookDto> httpEntity = getHttpEntity(bookDto);
ResponseEntity<Object> book = restTemplate.exchange(url,HttpMethod.POST,httpEntity,Object.class);
//Able to Get the response body in Object but if I try to change it to the Book the response body is coming null.
}
private HttpEntity<BookDto> getHttpEntity(BookDto bookDto) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Accept",MediaType.APPLICATION_JSON_VALUE);
return new HttpEntity<>(bookDto,headers);
}
#JsonInclude(JsonInclude.Include.NON_NULL)
public class APIResponse<T extends Object> implements Serializable {
/**
* status & message fields have not setter. They are assigned value when
* initial by APIStatus parameter
*/
private int status;
private String message;
private T data;
public APIResponse(APIStatus apiStatus, T data) {
if (apiStatus == null) {
throw new IllegalArgumentException("APIStatus must not be null");
}
this.status = apiStatus.getCode();
this.message = apiStatus.getDescription();
this.data = data;
}
public int getStatus() {
return status;
}
public String getMessage() {
return message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
public enum APIStatus {
// Common status
OK(200, null);
private final int code;
private final String description;
private APIStatus(int s, String v) {
code = s;
description = v;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
}
#Component
public class ResponseUtil {
private APIResponse<Book> createResponse(APIStatus apiStatus, Object data) {
return new APIResponse(apiStatus, data);
}
// base method
public ResponseEntity<APIResponse<Book>> buildResponse(APIStatus apiStatus, Object data, HttpStatus httpStatus) {
return new ResponseEntity(createResponse(apiStatus, data), httpStatus);
}
public ResponseEntity<APIResponse<Book>> successResponse(Object data) {
return buildResponse(APIStatus.OK, data, HttpStatus.OK);
}
}
#RestController
public class BookController {
#Autowired
BookService bookService;
#Autowired
protected ResponseUtil responseUtil;
#GetMapping("/books")
ResponseEntity<APIResponse<Book>> read(){
return responseUtil.successResponse(bookService.findAll());
}
}
I expect the response body result into the Book Object, not to the General Object class.
I am new to retrofit my aim is to display the data from a url using the retrofit library.
My Json data is:
`{
"RestResponse": {
"messages": [
"Total [249] records found."
],
"result": [
{
"name": "Afghanistan",
"alpha2_code": "AF",
"alpha3_code": "AFG"
},
{
"name": "��land Islands",
"alpha2_code": "AX",
"alpha3_code": "ALA"
},
{
"name": "Albania",
"alpha2_code": "AL",
"alpha3_code": "ALB"
},
{
"name": "Algeria",
"alpha2_code": "DZ",
"alpha3_code": "DZA"
},`
I would like to display the names of country in the LogCat and here are the gson converted Pojo classes
public class RestResponse {
#SerializedName("messages")
#Expose
private List<String> messages = null;
#SerializedName("result")
#Expose
private List<Result> result = null;
public List<String> getMessages() {
return messages;
}
public void setMessages(List<String> messages) {
this.messages = messages;
}
public List<Result> getResult() {
return result;
}
public void setResult(List<Result> result) {
this.result = result;
}
}
Second one Result.java:
public class Result {
#SerializedName("name")
#Expose
private String name;
#SerializedName("alpha2_code")
#Expose
private String alpha2Code;
#SerializedName("alpha3_code")
#Expose
private String alpha3Code;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAlpha2Code() {
return alpha2Code;
}
public void setAlpha2Code(String alpha2Code) {
this.alpha2Code = alpha2Code;
}
public String getAlpha3Code() {
return alpha3Code;
}
public void setAlpha3Code(String alpha3Code) {
this.alpha3Code = alpha3Code;
}
}
and Finally Movies.java //Example.java generated by Gson Converter:
public class Movies {
#SerializedName("RestResponse")
#Expose
private RestResponse restResponse;
public RestResponse getRestResponse() {
return restResponse;
}
public void setRestResponse(RestResponse restResponse) {
this.restResponse = restResponse;
}
}
From the above classes I am trying to retrieve the data. My RetrofitInstance is:
public class RetrofitInstance {
private static Retrofit retrofit = null;
private static String BASE_URL = "http://services.groupkt.com/";
public static ApiEndpoints getCombine() {
if (retrofit == null) {
retrofit = new Retrofit
.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit.create(ApiEndpoints.class);
}
}
and Endpoints Interface is:
public interface ApiEndpoints {
#GET("country/get/all")
Call<Movies> getResults();
}
and In MainActivity is used the following:
ApiEndpoints getCountryDataService= RetrofitInstance.getCombine();
Call<Movies> call=getCountryDataService.getResults();
call.enqueue(new Callback<Movies>() {
#Override
public void onResponse(Call<Movies> call, Response<Movies> response) {
Movies info=response.body();
if(info !=null && info.getRestResponse() != null){
results=(ArrayList<Result>) info.getRestResponse().getResult();
for(Result r:results){
Log.i("testing123","*********************************"+ r.getName());
}
}
}
#Override
public void onFailure(Call<Movies> call, Throwable t) {
Log.i("Error",t.fillInStackTrace()+"s");
t.fillInStackTrace();
}
});
Finally I am not able to print the countries in the Log. I am getting the following Error like
java.net.UnknownServiceException: CLEARTEXT communication to services.groupkt.com not permitted by network security policys
and iam new to retrofit concept.
Please help
Thanks in Advance.
I solved my problem by reducing the gradle version from
classpath 'com.android.tools.build:gradle:3.1.4'
to
classpath 'com.android.tools.build:gradle:3.1.2'
im using below code
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
WebTarget webTarget = client.target(uri);
Builder builder = webTarget.request();
Response response = builder.accept(MediaType.APPLICATION_JSON).get(Response.class);
final List<MyResponse> accountList = response.readEntity(new GenericType<List<MyResponse>>(){});
This returns accountList but all the values inside the list Objects were **null ie(Each property value inside MyResponse object is null)
But If i use below code
String myResponse = response
.readEntity(String.class);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MyResponse[] obj = mapper.readValue(myResponse, MyResponse[].class);
obj returns the proper array of Objects..but i dont want to read as string and deserialize..Please suggest!
Uri response is as follows
[
{
"type": "A1",
"attrs": {
"test_card": "Y"
}
}, {
"type": "A2"
"attrs": {
"issue_card": "N"
}
}
]
MyResponse Object
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyResponse implements Serializable {
#JsonProperty("type")
private String Type;
#JsonProperty("attrs")
private MyAttributes myAttributes;
public MyAttributes getattrs() {
return myAttributes;
}
public void setattrs(MyAttributes myAttributes) {
this.myAttributes = myAttributes;
}
public MyResponse() {
}
public String gettype() {
return Type;
}
public void settype(String Type) {
this.Type = Type;
}
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
}
MyAttributes Object
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyAttributes implements Serializable {
/**
*
*/
private static final long serialVersionUID = -4************;
#JsonProperty("test_card")
private String testCard;
public DecisionActionAttributes() {
}
public String getNewCardInd() {
return testCard;
}
public void setNewCardInd(String testCard) {
this.testCard = testCard;
}
#Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, false);
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
Given I have the following json:
{
"Company": {
"name": "cookieltd",
"type": "food",
"franchise_location": [
{
"location_type": "town",
"address_1": "5street"
},
{
"location_type": "village",
"address_1": "2road"
}
]
}
}
How can it be binded to the following object classes using Jackson?:
1) Company class
public class Company
{
String name, type;
List<Location> franchise_location = new ArrayList<Location>();
[getters and setters]
}
2) Location class
public class Location
{
String location_type, address_1;
[getters and setters]
}
I have done:
String content = [json above];
ObjectReader reader = mapper.reader(Company.class).withRootName("Company"); //read after the root name
Company company = reader.readValue(content);
but I am getting:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "franchise_location"
As far as I can tell, you are simply missing an appropriately named getter for the field franchise_location. It should be
public List<Location> getFranchise_location() {
return franchise_location;
}
(and the setter)
public void setFranchise_location(List<Location> franchise_location) {
this.franchise_location = franchise_location;
}
Alternatively, you can annotate your current getter or field with
#JsonProperty("franchise_location")
private List<Location> franchiseLocation = ...;
which helps to map JSON element names that don't really work with Java field name conventions.
The following works for me
public static void main(String[] args) throws Exception {
String json = "{ \"Company\": { \"name\": \"cookieltd\", \"type\": \"food\", \"franchise_location\": [ { \"location_type\": \"town\", \"address_1\": \"5street\" }, { \"location_type\": \"village\", \"address_1\": \"2road\" } ] } }";
ObjectMapper mapper = new ObjectMapper();
ObjectReader reader = mapper.reader(Company.class).withRootName(
"Company"); // read after the root name
Company company = reader.readValue(json);
System.out.println(company.getFranchise_location().get(0).getAddress_1());
}
public static class Company {
private String name;
private String type;
private List<Location> franchise_location = new ArrayList<Location>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Location> getFranchise_location() {
return franchise_location;
}
public void setFranchise_location(List<Location> franchise_location) {
this.franchise_location = franchise_location;
}
}
public static class Location {
private String location_type;
private String address_1;
public String getLocation_type() {
return location_type;
}
public void setLocation_type(String location_type) {
this.location_type = location_type;
}
public String getAddress_1() {
return address_1;
}
public void setAddress_1(String address_1) {
this.address_1 = address_1;
}
}
and prints
5street
my solution for JSON is always GSON, you can do some research on that, as long as you have the correct structure of class according to the JSON, it can automatically transfer from JSON to object:
Company company = gson.fromJson(json, Company.class);
GSON is so smart to do the convertion thing!
enjoy GSON !