convert JSON from ajax request to JSON object in java - java

This is the form data
selectedDtlId: [{"id":"3","isReviewed":true,"notes":"notes asdf test add 2"},{"id":"2","isReviewed":true,"notes":""},{"id":"1","isReviewed":true,"notes":""}]
isReviewedAll: true
notesAll:
Upon running the below code in the Controller
Gson gson = new Gson();
gson.toJson(request.getParameter("selectedDtlId"));
response
"[{\"id\":\"3\",\"isReviewed\":true,\"notes\":\"notes asdf test add 2\"},{\"id\":\"2\",\"isReviewed\":true,\"notes\":\"\"},{\"id\":\"1\",\"isReviewed\":true,\"notes\":\"\"}]"
Expected resoponse
[
{
"id": "3",
"isReviewed": true,
"notes": "notes asdf test add 2"
},
{
"id": "2",
"isReviewed": true,
"notes": ""
},
{
"id": "1",
"isReviewed": true,
"notes": ""
}
]

You're calling toJson when you should be calling fromJson:
gson.fromJson(request.getParameter("selectedDtlId"), JsonElement.class);
Or if you have a model:
gson.fromJson(request.getParameter("selectedDtlId"), MyModel.class);

You should map it to a Class. (Also you are calling toJson when you should call fromJson)
Main
import com.google.gson.Gson;
public class Main {
public static void main(String[] args) {
String jsonInString = "[{\"id\":\"3\",\"isReviewed\":true,\"notes\":\"notes asdf test add 2\"},{\"id\":\"2\",\"isReviewed\":true,\"notes\":\"\"},{\"id\":\"1\",\"isReviewed\":true,\"notes\":\"\"}]";
Gson gson = new Gson();
SelectedDtlId[] selectedDtlIds = gson.fromJson(jsonInString, SelectedDtlId[].class);
for (SelectedDtlId selectedDtlId : selectedDtlIds) {
System.out.println("id: " + selectedDtlId.getId());
System.out.println("notes: " + selectedDtlId.getNotes());
System.out.println("isReviewed: " + selectedDtlId.isReviewed());
}
}
}
Model
import com.google.gson.annotations.SerializedName;
public class SelectedDtlId {
#SerializedName("id")
private int id;
#SerializedName("isReviewed")
private boolean isReviewed;
#SerializedName("notes")
private String notes;
// getters & setters
}
the result should be:
id: 3
notes: notes asdf test add 2
isReviewed: true
id: 2
notes:
isReviewed: true
id: 1
notes:
isReviewed: true

Related

Trouble deserializing JSON into Java objects with GSON

I have been trying to learn GSON, but I am struggling with it. I am trying to deserialize a JSON file into Java objects, using GSON. I have read a million other questions on here, and for the life of me, I can't understand what I'm doing wrong.
Here is my JSON text:
{
"movies": [
{
"name": "The Shawshank Redemption",
"url": "https://parsehub.com/sandbox/moviedetails?movie=The%20Shawshank%20Redemption",
"IMAX": "06:00 PM",
"rating": "9 . 2",
"cast": [
{
"character": "Andy Dufresne",
"actor": "Tim Robbins"
},
{
"character": "Ellis Boyd 'Red' Redding",
"actor": "Morgan Freeman"
},
{
"character": "Warden Norton",
"actor": "Bob Gunton"
},
{
"character": "Heywood",
"actor": "William Sadler"
}
]
},
{
"name": "Schindler's List",
"url": "https://parsehub.com/sandbox/moviedetails?movie=Schindler%27s%20List",
"IMAX": "06:15 PM",
"rating": "8 . 9",
"cast": [
{
"character": "Oskar Schindler",
"actor": "Liam Neeson"
},
{
"character": "Itzhak Stern",
"actor": "Ben Kingsley"
},
{
"character": "Amon Goeth",
"actor": "Ralph Fiennes"
}
]
}
]
}
And here is my Java code:
import com.google.gson.Gson;
import java.io.*;
import java.lang.reflect.Type;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) throws FileNotFoundException {
Gson gson = new Gson();
Movies[] movies = gson.fromJson(new FileReader("src/main/input.json"), (Type) Movies.class);
System.out.println(movies[0]);
}
class Movies {
String name;
String url;
String IMAX;
String rating;
ArrayList<Cast> cast;
}
class Cast {
ArrayList<CastMember> castMembers;
}
class CastMember{
String character;
String actor;
}
}
When I run this, I get the following error:
Exception in thread "main" java.lang.ClassCastException: class com.Main$Movies cannot be cast to class [Lcom.Main$Movies; (com.Main$Movies and [Lcom.Main$Movies; are in unnamed module of loader 'app')
at com.Main.main(Main.java:13)
The JSON you are deserializing represents an object with a list of objects on it. The Java object you are trying to deserialize to needs to match that.
First, create a new class MovieList.
class MovieList {
List<Movie> movies;
}
Update your Movies class to be called Movie, since it represents a single movie.
class Movie {
String name;
String url;
String IMAX;
String rating;
List<Cast> cast;
}
Now try calling gson.fromJson(...) with the following
MovieList movieList = gson.fromJson(new FileReader("src/main/input.json"), MovieList.class);
System.out.println(movieList.getMovies().get(0));
Try using this
Gson gson = new Gson();
Movies[] movies = gson.fromJson(new JsonReader(new FileReader("src/main/input.json"))),Movies[].class);
or something like
Type listType = new TypeToken<List<Movies>>() {}.getType();
List<Movies> movies = new Gson().fromJson(new JsonReader(new FileReader("src/main/input.json"))), listType);

Filter JSON by value spring java

I'm trying to filter an incoming JSON by it's value. This is the current JSON that I generate by receiven a huge JSON from an jira api. I have a few POJO classes that handle the response and get only the fields I need for now. But I need the "fromString" and "toString" keys which only contain a handful Strings, like "To Do", "Done", "QA To Do". I tried using FilterProvider but I don't know how to filter by value and then add it to my GetMapping.
This is my current GetMapping in my controller class, which creates a response and filters the items[] only for the key "fromString":
#GetMapping("/")
public MappingJacksonValue run() throws Exception {
IssuesList response = rest.getForObject(
"https://.../rest/api/2/search?jql=project="+projectId+ " AND status in (done) AND issuetype in (Story)&expand=changelog",
IssuesList.class);
List<Issues> issuesData = response.getIssuesList();
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(issuesData);
FilterProvider filterProvider = new SimpleFilterProvider().addFilter("itemsEntity", SimpleBeanPropertyFilter.filterOutAllExcept("fromString"));
mappingJacksonValue.setFilters(filterProvider);
log.info(mappingJacksonValue.toString());
return mappingJacksonValue;
}
My Pojo class with items:
#Data
#JsonFilter("itemsEntity")
#JsonIgnoreProperties(ignoreUnknown = true)
public class Items {
#JsonProperty("fromString")
private String fromString;
#JsonProperty("toString")
private String toString;
#Override
public String toString() {
return "{" +
"fromString= " + '\'' + fromString+ '\'' +
", toString= " + '\'' + toString + '\'' +
'}';
}
}
This is the current JSON that I produce from the response I get, I want it to skip all "fromString" and "toString" keys which do not contain one of the following: "To Do", "Done","Qa To Do", etc.
How do I achieve that?
[
{
"key": "PE-1322",
"fields": {
"issuetype": {
"name": "Story"
},
"created": "2020-11-18T09:16:55.816+0000",
"customfield_10105": 3
},
"changelog": {
"histories": [
{
"created": "2020-12-17T08:57:28.800+0000",
"items": [
{
"fromString": "This issue relates to TD-353"
}
]
},
{
"created": "2020-12-17T08:57:19.233+0000",
"items": [
{
"fromString": null
}
]
}
]
}
}
]
You will need to write your own Filter that uses a comparator that suits your needs.
For example:
filteredList = Arrays.stream(unfilteredList).filter(listItem -> listItem.contains("To Do")).toArray(String[]::new);
In this case the filter will filter out anything that doesn't contain the string "To Do".

Rest Assured: extract value from Response List

I have a List returned as response. I need to get one item from list using product.name and tariffPlan.name.
[
{
"id": 123,
"product": {
"id": 1,
"code": "credit",
"name": "Credit"
},
"tariffPlan": {
"id": 1,
"code": "gold",
"name": "Gold"
}
},
{
"id": 234,
"product": {
"id": 2,
"code": "debit",
"name": "Debit"
},
"tariffPlan": {
"id": 1,
"code": "gold",
"name": "Gold"
}
}
]
I use Java8. Here is my method. I got List of Card.class elements. And then I need to get single Item from list with specified "product.name" and "tariffPlan.name".
public List<Card> getCardId(String productName, String tariffPlanName) {
return given()
.param("product.name", productName)
.param("tariffPlan.name", tariffPlanName)
.when().get("/").then()
.extract().jsonPath().getList("", Card.class);
}
Is it possible to do it with restAssured? Maybe use .param method like in my example? But in my example .param method is ignored. Thank you for your ideas.
UPD. My decision is:
public Card getCard(String productName, String tariffPlanName) {
List<Card> cardList = given()
.when().get("/").then()
.extract().jsonPath().getList("", Card.class);
return cardList.stream()
.filter(card -> card.product.name.equals(productName))
.filter(card -> card.tariffPlan.name.equals(tariffPlanName))
.findFirst()
.get();
}
If you need to get a value from response json list, here's what worked for me:
Json sample:
[
{
"first": "one",
"second": "two",
"third": "three"
}
]
Code:
String first =
given
.contentType(ContentType.JSON)
.when()
.get("url")
.then()
.extract().response().body().path("[0].first")
Actually, you can but... you need to handle deserialization issue of default mapper becase if you try do the following:
.extract().jsonPath().getList("findAll {it.productName == " + productName + "}", Card.class);
You will failing on converting HashMap to your object type. It happens because of using gpath expression in path provides json without double quotes on keys by default. So you need to prettify it with (you can put it in RestAssured defaults):
.extract().jsonPath().using((GsonObjectMapperFactory) (aClass, s) -> new GsonBuilder().setPrettyPrinting().create())
And as result your would be able to cast things like that:
.getObject("findAll {it.productName == 'productName'}.find {it.tariffPlanName.contains('tariffPlanName')}", Card.class)
See full example:
import com.google.gson.GsonBuilder;
import io.restassured.http.ContentType;
import io.restassured.mapper.factory.GsonObjectMapperFactory;
import lombok.Data;
import org.testng.annotations.Test;
import java.util.HashMap;
import java.util.List;
import static io.restassured.RestAssured.given;
public class TestLogging {
#Test
public void apiTest(){
List<Item> list = given()
.contentType(ContentType.JSON)
.when()
.get("https://jsonplaceholder.typicode.com/posts")
.then().log().all()
.extract().jsonPath().using((GsonObjectMapperFactory) (aClass, s) -> new GsonBuilder().setPrettyPrinting().create())
.getList("findAll {it.userId == 6}.findAll {it.title.contains('sit')}", Item.class);
list.forEach(System.out::println);
}
#Data
class Item {
private String userId;
private String id;
private String title;
private String body;
}
}
Here a kotlin example:
#Test
fun `creat endpoint with invalid payload should return 400 error`() {
val responseError: List<ErrorClass> = Given {
spec(requestSpecification)
body(invalidPayload)
} When {
post("/endpoint")
} Then {
statusCode(HttpStatus.SC_BAD_REQUEST)
} Extract {
body().`as`(object : TypeRef<List<ErrorClass>>() {})
}
responseError shouldHaveSize 1
responseError[0].field shouldBe "xxxx"
responseError[0].message shouldBe "xxx"
}
Suppose you want to fetch the value of the id, when product name is "Credit" and tariffPlan is "Gold".
Use
from(get(url).asString()).getList("findAll { it.product.name == 'Credit' && it.tariffPlan.name == 'Gold'}.id");
Where url - http/https request and get(url).asString() will return a JSON response as string.

How to parse JSON String to java object with jackson?

I am currently having trouble trying to parse this VCAP_SERVICES to java objects. I do not quite understand how to structure the POJO to allow it to map the values from the json string. Can someone please help me structure my pojo so that it is aligns with the json string?
I want to create objects for both of the credentials: accessToken... jdbcurl.
VCAP_SERVICES
"VCAP_SERVICES": {
"user-provided": [
{
"credentials": {
"accessTokenUri": "tokenurl",
"apiUrl": "apiurl",
"clientId": "typeofID",
"clientSecret": "secretAf",
"scope": "none"
},
"syslog_drain_url": "",
"volume_mounts": [],
"label": "user-provided",
"name": "OAuth2",
"tags": []
},
{
"credentials": {
"jdbcUrl": "jdbc:oracle:connection[host]:[port]/service",
"spring.datasource.driver-class-name": "oracle.jdbc.OracleDriver",
"spring.datasource.initialize": "false"
},
"syslog_drain_url": "",
"volume_mounts": [],
"label": "user-provided",
"name": "Database",
"tags": []
}
]
Java Class
ObjectMapper mapper = new ObjectMapper();
//json String to Object
CupsProperties properties = mapper.readValue(VCAP_Services, CupsProperties.class);
System.out.println(properties.getJdbcUrl() + "!!!!!!!!!!!!!!!!!!!");
POJOS
public class UserProviderWrapper {
#JsonProperty("user-provided")
public List<CupsProperties> cupsProperties;
#JsonProperty("syslog_drain_url")
public String syslog_drain_url;
#JsonProperty("volume_mounts")
public List<String> volume_mounts;
#JsonProperty("label")
public String label;
#JsonProperty("name")
public String name;
#JsonProperty("tags")
public List<String> tags;
//getters and setters
public class CupsProperties {
#JsonProperty("jdbcUrl")
public String jdbcUrl;
#JsonProperty("spring.datasource.driver-class-name")
public String driver;
#JsonProperty("spring.datasource.initialize")
public String initialize;
//getters and setters
Error
Unrecognized field "user-provided" (class rest.springframework.model.CupsProperties), not marked as ignorable (2 known properties: "jdbcUrl", "dataSource"])
at [Source: {"user-provided":[{ "credentials": { "jdbcUrl": "jdbc:oracle:thin:user/pass//host:port/service", "spring.datasource.driver-class-name": "oracle.jdbc.OracleDriver", "spring.datasource.initialize": "false" }, "syslog_drain_url": "", "volume_mounts": [ ], "label": "user-provided", "name": "Oracle", "tags": [ ] }]}; line: 1, column: 19] (through reference chain: rest.springframework.model.CupsProperties["user-provided"])
Check below solution and see if it fulfills your need. You can build on to it if you need to parse more fields.
import java.util.Iterator;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
public class JsonParser {
public static void main(String[] args) {
String VCAP_Services = "{\"userProvided\": [{\"credentials\": {\"accessTokenUri\": \"tokenurl\",\"apiUrl\": \"apiurl\",\"clientId\": \"typeofID\",\"clientSecret\": \"secretAf\",\"scope\": \"none\"},\"syslog_drain_url\": \"\",\"volume_mounts\": [],\"label\": \"user-provided\",\"name\": \"OAuth2\",\"tags\": []},{\"credentials\": {\"jdbcUrl\": \"jdbc:oracle:connection[host]:[port]/service\",\"spring.datasource.driver-class-name\": \"oracle.jdbc.OracleDriver\",\"spring.datasource.initialize\": \"false\"},\"syslog_drain_url\": \"\",\"volume_mounts\": [],\"label\": \"user-provided\",\"name\": \"Database\",\"tags\": [] } ] } ";
CupsProperties properties=null;
try {
JSONParser jsonParser = new JSONParser();
JSONObject vcapServiceJSONObject = (JSONObject) jsonParser.parse(VCAP_Services);
for(Object key: vcapServiceJSONObject.keySet()){
String keyStr = (String) key;
JSONArray userProvidedList = (JSONArray) vcapServiceJSONObject.get(keyStr);
Iterator i = userProvidedList.iterator();
while (i.hasNext()) {
JSONObject innerObj = (JSONObject) i.next();
JSONObject credentialsObject = (JSONObject) innerObj.get("credentials");
if(credentialsObject.containsKey("jdbcUrl")){
//set to your pojo objects
System.out.println("JDBC url:" + credentialsObject.get("jdbcUrl"));
}
if(credentialsObject.containsKey("accessTokenUri")){
//set to your pojo objects
System.out.println("Access token URI:" + credentialsObject.get("accessTokenUri"));
}
}
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
Output
Access token URI:tokenurl
JDBC url:jdbc:oracle:connection[host]:[port]/service

Spring RestTemplate parse JSON object with variable keyname

I have a REST API call that returns the following JSON object. I need to parse this with Spring's RestTemplate. The problem is that the first key ISBN:0132856204 is variable (the numbers change depending on the book). How would I go about doing this?
{
"ISBN:0132856204": {
"publishers": [
{
"name": "Pearson"
}
],
"pagination": "xxiv, 862p",
"identifiers": {
"isbn_13": [
"978-0-13-285620-1"
],
"openlibrary": [
"OL25617855M"
]
},
"weight": "1340 grams",
"title": "Computer networking",
"url": "https://openlibrary.org/books/OL25617855M/Computer_networking",
"number_of_pages": 862,
"cover": {
"small": "https://covers.openlibrary.org/b/id/7290810-S.jpg",
"large": "https://covers.openlibrary.org/b/id/7290810-L.jpg",
"medium": "https://covers.openlibrary.org/b/id/7290810-M.jpg"
},
"publish_date": "2013",
"key": "/books/OL25617855M",
"authors": [
{
"url": "https://openlibrary.org/authors/OL31244A/James_F._Kurose",
"name": "James F. Kurose"
},
{
"url": "https://openlibrary.org/authors/OL658909A/Keith_W._Ross",
"name": "Keith W. Ross"
}
],
"subtitle": "A Top-Down Approach"
}
}
In here "ISBN:0132856204" is a value and also a key for your business.
To get ISBN first, what about wrapping json content with 1 more closure?
{
"yourAwesomePlaceHolderKey" :
{
"ISBN:0132856204": {
......
}
}
}
First get the ISBN key as a value, then your ISBN value can be used as a key to get related content.
First goal will be extracting -String1,Object1- pair where String1 is "yourAwesomePlaceholderKey" and second goal will be again extracting -String2,Object2- from Object1 where String2 is your ISBN key.
This is the way I solved it, using JsonPath for getting the book out of the JSON object and Jackson for mapping it to a Book object:
RestTemplate restTemplate = new RestTemplate();
String isbn = "0132856204";
String endpoint = "https://openlibrary.org/api/books?jscmd=data&format=json&bibkeys=ISBN:{isbn}";
//Get JSON as String
String jsonString = restTemplate.getForObject(endpoint, String.class, isbn);
//Configure JsonPath to use Jackson for mapping
Configuration.setDefaults(new Configuration.Defaults() {
private final JsonProvider jsonProvider = new JacksonJsonProvider();
private final MappingProvider mappingProvider = new JacksonMappingProvider();
#Override
public JsonProvider jsonProvider() {
return jsonProvider;
}
#Override
public MappingProvider mappingProvider() {
return mappingProvider;
}
#Override
public Set<Option> options() {
return EnumSet.noneOf(Option.class);
}
});
//Parse the JSON as a book
Book book = JsonPath.parse(jsonString).read("$.ISBN:" + isbn, Book.class);
You can use JsonProperty to solve
#JsonProperty("ISBN:0132856204")

Categories