How can i use replace in JSON? - java

Heyy,
I have a JSON String i.e.
{"userId":"WaNenOnQt","photos":[{"photo_url":"vendor_photos/WaNenOnQt/web_(138)(4thcopy).JPG","index":1},{"photo_url":"vendor_photos/WaNenOnQt/54230451_265006064447640_7942942433146217157_n.jpg","index":2}]}
I want only the List data i.e. -
[{"photo_url":"vendor_photos/WaNenOnQt/web_(138)(4thcopy).JPG","index":1},{"photo_url":"vendor_photos/WaNenOnQt/54230451_265006064447640_7942942433146217157_n.jpg","index":2}]
Is there any replace function in java or how can i segregate the list ?

assuming you are getting that JSON through an endpoint you are exposing, you should bind it to the method signature, for example if you are using Spring:
public class MyPojo {
private String userId;
private List<Photo> photoList;
//getters & setters
}
Photo class
public class Photo {
#JsonProperty("photo_url")
private String url;
private int index;
//getters & setters
}
Controller class
#RequestMapping(value = "/test", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> test(#RequestBody MyPojo request) {
List<Photo> photos = request.getPhotoList();
}
Alternatively if you don't have an endpoint, you can manually transform the JSON String to a POJO and vice-versa, using Java's ObjectMapper. For example:
public void transform(String jsonString) throws... {
ObjectMapper mapper = new ObjectMapper();
MyPojo pojo = mapper.readValue(jsonString, MyPojo.class);
List<Photo> photo = pojo.getPhotoList();
}
I'm also assuming that you need a Java List, and don't need the JSON array simply as a String.

You van use small json library
String jsonstring = "{\"userId\":\"WaNenOnQt\",\"photos\":[{\"photo_url\":\"vendor_photos/WaNenOnQt/web_(138)(4thcopy).JPG\",\"index\":1},{\"photo_url\":\"vendor_photos/WaNenOnQt/54230451_265006064447640_7942942433146217157_n.jpg\",\"index\":2}]}";
JsonValue json = JsonParser.parse(jsonstring);
JsonValue photos = json.asObject().first("photos");
String result = photos.toCompactString();

Related

Can not find a (Map) Key deserializer for type [simple type, class com.example.app.ReferralApiModel]

I'm trying to fetch JSON data from my website throw REST API with retrofit2.
But when I run the app this error message show:
Can not find a (Map) Key deserializer for type [simple type, class com.example.app.ReferralApiModel]
I'm using retrofit library.
This is my code for the retrofit call:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(AppConfig.URL)
.addConverterFactory(JacksonConverterFactory.create())
.client(defaultHttpClient)
.build();
ReferralsPlaceHolderApi placeHolderApi = retrofit.create(ReferralsPlaceHolderApi.class);
Call<List<Map<ReferralApiModel, String>>> call = placeHolderApi.getReferrals();
And this is my ReferralsPlaceHolderApi class:
public interface ReferralsPlaceHolderApi {
#JsonDeserialize(keyAs = ReferralsCustomDeserializer.class)
#GET(AppConfig.ENDPOINT_REFERRALS)
Call<List<Map<ReferralApiModel, String>>> getReferrals();
}
Also this is my ReferralApiModel class:
public class ReferralApiModel {
private String date;
private String amount;
private String currency;
private String status;
public ReferralApiModel() {}
public ReferralApiModel(String date, String amount, String currency, String status) {
this.date = date;
this.amount = amount;
this.currency = currency;
this.status = status;
}
public String getDate() {
return date;
}
public String getAmount() {
return amount;
}
public String getCurrency() {
return currency;
}
public String getStatus() {
return status;
}
}
This is the json data that I'm trying to get:
"[{\"id\":\"1\",\"refferal_wp_uid\":\"0\",\"campaign\":\"\",\"affiliate_id\":\"5\",\"visit_id\":\"1\",\"description\":\"\",\"source\":\"woo\",\"reference\":\"302\",\"reference_details\":\"68\",\"parent_referral_id\":\"0\",\"child_referral_id\":\"0\",\"amount\":\"1500.00\",\"currency\":\"\د\ج\",\"date\":\"2022-01-31 12:53:29\",\"status\":\"0\",\"payment\":\"0\",\"username\":\"aaa\"},{\"id\":\"2\",\"refferal_wp_uid\":\"0\",\"campaign\":\"\",\"affiliate_id\":\"5\",\"visit_id\":\"2\",\"description\":\"\",\"source\":\"woo\",\"reference\":\"303\",\"reference_details\":\"68\",\"parent_referral_id\":\"0\",\"child_referral_id\":\"0\",\"amount\":\"1500.00\",\"currency\":\"\د\ج\",\"date\":\"2022-01-31 13:03:43\",\"status\":\"1\",\"payment\":\"0\",\"username\":\"aaa\"},{\"id\":\"3\",\"refferal_wp_uid\":\"0\",\"campaign\":\"\",\"affiliate_id\":\"5\",\"visit_id\":\"2\",\"description\":\"\",\"source\":\"woo\",\"reference\":\"304\",\"reference_details\":\"68\",\"parent_referral_id\":\"0\",\"child_referral_id\":\"0\",\"amount\":\"1500.00\",\"currency\":\"\د\ج\",\"date\":\"2022-01-31 13:04:33\",\"status\":\"2\",\"payment\":\"0\",\"username\":\"aaa\"}]"
Can anyone help me with this?.
Also I've found that this problem may be a class mapping problem, from this answer :
https://stackoverflow.com/a/16383752/8055951
If it's ?!, Can someone tell me how to map the ReferralsPlaceHolderApi class.
Thanks.
Jackson cannot deserialize custom classes as map keys. The key of your deserialized map is ReferralApiModel. I order to achieve it, you need to write your own KeyDeserializer and register it for your class with Jackson. You can see here or here how to do that.
Also the json string in the question makes it look as if you don't need to deserialize into List<Map<ReferralApiModel, String>>, but into List<ReferralApiModel> instead. Which would make writing custom key deseriaslizers redundant.
Edit: Ok, receiving json array, which has been json sting-ified is just strange. It would be best, if someone on your team is responsible for this API and can fix it. If not, you have workarounds:
Parse twice with object mapper - first parse it to normal string, which would be json array, then parse this string into List<YourObject>
ObjectMapper mapper = new ObjectMapper();
String string = mapper.readValue(initialJson, String.class);
List<ReferralApiModel> list = mapper.readValue(string, TypeFactory.defaultInstance().constructCollectionType(List.class, ReferralApiModel.class));
list.forEach(System.out::println);
Turn it manually into proper json array. That means remove first and last char - double quote, and remove all those escapes - \. Something like this:
String jsonString = "the string";
jsonString = jsonString.substring(1, jsonString.length() - 1).replace("\\", "");
ObjectMapper mapper = new ObjectMapper();
List<ReferralApiModel> list = mapper.readValue(jsonString, TypeFactory.defaultInstance().constructCollectionType(List.class, ReferralApiModel.class));
list.forEach(System.out::println);

Multiple DTOs manual initialize

in Microservice, we post multiple dtos data as string json.
Controller:
#RequestMapping(value="/json",method = RequestMethod.POST)
public String getjson(#RequestBody String json) {
///Service process
}
Post Json:
{
"dtos":{
"Dto1":{
"name":"Dto1 Name Field",
"filter":[
{"key":"f1","value":1},
{"key":"f2","value":10}
]
},
"Dto2":{
"city":"Newyork",
"filter":[
{"key":"f1","value":1},
{"key":"f2","value":10},
{"key":"f3","value":10}
]
}
},
"page":1
}
DTO:
public class Dto1{
private String name;
}
public class Dto2{
private String city;
}
Dto1 and Dto2 is java DTO object name.
how to convert string json to java objects?
You can create a new DTO that contains all attrs and receive in request:
public class Filter{
private String key;
private int value;
}
public class Dto1{
private String name;
private List<Filter> filter;
}
public class Dto2{
private String city;
private List<Filter> filter;
}
public class Dtos{
public Dto1 dto1;
public Dto2 dto2;
}
public class DtoToReceiveInRequest{
private Dtos dtos;
private int page;
}
Controller
#PostMapping
public String getjson(#RequestBody DtoToReceiveInRequest json) {
///Service process
}
You can use the ObjectMapper from the jackson library, like below.
String json = "";
ObjectMapper objectMapper = new ObjectMapper();
Dto1 dto = objectMapper.readValue(json, Dto1.class);
But in your particular example, you don't have to have two DTO classes. You can encapsulate values in one DTO and have the list of different instances of that DTO in a json format.
NB. The json string should be a representation of the preferred class you want to retrieve, eg Dto1.java.

How to convert embedded JSON String inside JSON to java object?

I have the below json, where the body key contains a value which is a string representation of a JSON object, how do I convert it to a Java Object ?
I can extract the body value by converting the JSON to a Map, but I don't know how I should proceed from there
input.json file
{
"body": "{\n\t\"username\": \"TestUser\",\n\t\"password\": \"TestPassword\"\n}"
}
The User POJO is as below,
class User {
private String username;
private String password;
... getters, setters and no-arg constructor
}
My code looks something like this, I need to implement convertToUser function
public static void main(String[] args) {
String jsonContent = readJsonFile("input.json");
String escapedJsonBody = getBody(s);
User user = convertToUser(escapedJsonBody, User.class);
}
I am already using jackson java library, any insights on doing this with jackson is highly appreciated.
One way to do it is to create DTOs and converter. Having DTOs like (i have nested the class declarations jsut to save space in answer):
#Getter #Setter
public class Input { // this level maps to the whole input.json
#JsonDeserialize(using = BodyDeserializer.class) // custom deserializer below
private Body body; // this is the body-attribute in JSON
#Getter #Setter
public static class Body {
private User user;
#Getter #Setter
public static class User {
private String username;
private String password;
}
}
}
the converter:
public class BodyDeserializer extends JsonDeserializer<Body> {
private ObjectMapper om = new ObjectMapper(); // this is to read the user from string
#Override
public Body deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String embedded = p.readValueAs(String.class);
Body body = new Body();
body.setUser(om.readValue(embedded, User.class)); // here is the trick
return body;
}
}
Use like:
ObjectMapper om = new ObjectMapper();
String input = "{\"body\": \"{\\n\\t\\\"username\\\": \\\"TestUser\\\",\\n\\t\\\"password\\\": \\\"TestPassword\\\"\\n}\"}";
Input r = om.readValue(input, Input.class);
This way the conversion happens in generic way only con might be that you do not like to create DTOs and dig the user like Input.getBody().getUser();
To convert a JSON String to a java pojo you can use Jackson's ObjectMapper class that will assist you to do this.
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.readValue(inputJson, User.class);
More info can be found on Jackson's github page

Deserialize nested array as ArrayList with Jackson

I have a piece of JSON, that looks like this:
{
"authors": {
"author": [
{
"given-name": "Adrienne H.",
"surname": "Kovacs"
},
{
"given-name": "Philip",
"surname": "Moons"
}
]
}
}
I have created a class to store Author information:
public class Author {
#JsonProperty("given-name")
public String givenName;
public String surname;
}
And two wrapper classes:
public class Authors {
public List<Author> author;
}
public class Response {
public Authors authors;
}
This is working, but having two wrapper classes seems to be unnecessary. I want to find a way to remove Authors class and have a list as a property of Entry class. Is something like that is possible with Jackson?
Update
Solved that with custom deserializer:
public class AuthorArrayDeserializer extends JsonDeserializer<List<Author>> {
private static final String AUTHOR = "author";
private static final ObjectMapper mapper = new ObjectMapper();
private static final CollectionType collectionType =
TypeFactory
.defaultInstance()
.constructCollectionType(List.class, Author.class);
#Override
public List<Author> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException, JsonProcessingException {
ObjectNode objectNode = mapper.readTree(jsonParser);
JsonNode nodeAuthors = objectNode.get(AUTHOR);
if (null == nodeAuthors // if no author node could be found
|| !nodeAuthors.isArray() // or author node is not an array
|| !nodeAuthors.elements().hasNext()) // or author node doesn't contain any authors
return null;
return mapper.reader(collectionType).readValue(nodeAuthors);
}
}
And using it like this:
#JsonDeserialize(using = AuthorArrayDeserializer.class)
public void setAuthors(List<Author> authors) {
this.authors = authors;
}
Thanks #wassgren for the idea.
I see at least two approaches to do this if you want to get rid of wrapper classes. The first is to use the Jackson Tree Model (JsonNode) and the second is to use a deserialization feature called UNWRAP_ROOT_VALUE.
Alternative 1: Use JsonNode
When deserializing JSON using Jackson there are multiple ways to control what type of objects that are to be created. The ObjectMapper can deserialize the JSON to e.g. a Map, JsonNode (via the readTree-method) or a POJO.
If you combine the readTree-method with the POJO conversion the wrappers can be completely removed. Example:
// The author class (a bit cleaned up)
public class Author {
private final String givenName;
private final String surname;
#JsonCreator
public Author(
#JsonProperty("given-name") final String givenName,
#JsonProperty("surname") final String surname) {
this.givenName = givenName;
this.surname = surname;
}
public String getGivenName() {
return givenName;
}
public String getSurname() {
return surname;
}
}
The deserialization can then look something like this:
// The JSON
final String json = "{\"authors\":{\"author\":[{\"given-name\":\"AdrienneH.\",\"surname\":\"Kovacs\"},{\"given-name\":\"Philip\",\"surname\":\"Moons\"}]}}";
ObjectMapper mapper = new ObjectMapper();
// Read the response as a tree model
final JsonNode response = mapper.readTree(json).path("authors").path("author");
// Create the collection type (since it is a collection of Authors)
final CollectionType collectionType =
TypeFactory
.defaultInstance()
.constructCollectionType(List.class, Author.class);
// Convert the tree model to the collection (of Author-objects)
List<Author> authors = mapper.reader(collectionType).readValue(response);
// Now the authors-list is ready to use...
If you use this Tree Model-approach the wrapper classes can be completely removed.
Alternative 2: remove one of the wrappers and unwrap the root value
The second approach is to remove only one of the wrappers. Assume that you remove the Authors class but keep the Response-wrapper. If you add the a #JsonRootName-annotation you can later unwrap the top-level name.
#JsonRootName("authors") // This is new compared to your example
public class Response {
private final List<Author> authors;
#JsonCreator
public Response(#JsonProperty("author") final List<Author> authors) {
this.authors = authors;
}
#JsonProperty("author")
public List<Author> getAuthors() {
return authors;
}
}
Then, for your mapper simply use:
ObjectMapper mapper = new ObjectMapper();
// Unwrap the root value i.e. the "authors"
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
final Response responsePojo = mapper.readValue(json, Response.class);
The second approach only removes one of the wrapper classes but instead the parsing function is quite pretty.

How to extract property from JSON embedded within JSON?

This is the JSON String I am getting back from a URL and I would like to extract highDepth value from the below JSON String.
{
"description": "",
"bean": "com.hello.world",
"stats": {
"highDepth": 0,
"lowDepth": 0
}
}
I am using GSON here as I am new to GSON. How do I extract highDepth from the above JSON Strirng using GSON?
String jsonResponse = restTemplate.getForObject(url, String.class);
// parse jsonResponse to extract highDepth
You create a pair of POJOs
public class ResponsePojo {
private String description;
private String bean;
private Stats stats;
//getters and setters
}
public class Stats {
private int highDepth;
private int lowDepth;
//getters and setters
}
You then use that in the RestTemplate#getForObject(..) call
ResponsePojo pojo = restTemplate.getForObject(url, ResponsePojo.class);
int highDepth = pojo.getStats().getHighDepth();
No need for Gson.
Without POJOs, since RestTemplate by default uses Jackson, you can retrieve the JSON tree as an ObjectNode.
ObjectNode objectNode = restTemplate.getForObject(url, ObjectNode.class);
JsonNode highDepth = objectNode.get("stats").get("highDepth");
System.out.println(highDepth.asInt()); // if you're certain of the JSON you're getting.
Refering to JSON parsing using Gson for Java, I would write something like
JsonElement element = new JsonParser().parse(jsonResponse);
JsonObject rootObject = element.getAsJsonObject();
JsonObject statsObject = rootObject.getAsJsonObject("stats");
Integer highDepth = Integer.valueOf(statsObject.get("highDepth").toString());

Categories