I have been struggling with converting the below json .
Is the data class should be mapped as Map<String,Object>.Then use Object mapper class to all values?What is the best way to map below pojo
Json Response
{
"data": {
"Order": [
{
{
"Property1" : Number1
"Propery2": Number 2
},
"Lines": [
{
"Id": "123456",
"itemDescription": "Green glass",
}
],
"date": "",
"updateDate": ""
}
]
}
}
Data class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Details {
public Map<String,Object> data;
}
Related
I have data saved into Realtime Firebase as an iterative JSON as shown in the picture.
Realtime Firebase data
[
{
"name": "Math",
"subMenu": [
{
"name": "Math1",
"subMenu": [
{
"name": "Math 1.1"
},
{
"name": "Math 1.2",
"subMenu": [
{
"name": "Math 1.2.1",
"subMenu": [
{
"name": "Math 1.2.1.1"
},
{
"name": "Math 1.2.1.2"
}
]
},
{
"name": "Math 1.2.2"
}
]
}
]
},
{
"name": "Math2"
},
{
"name": "Math3",
"subMenu": [
{
"name": "Math 1.3.1"
},
{
"name": "Math 1.3.2"
}
]
}
]
},
{
"name": "Marketing",
"subMenu": [
{
"name": "Promotions",
"subMenu": [
{
"name": "Catalog Price Rule"
},
{
"name": "Cart Price Rules"
}
]
},
{
"name": "Communications",
"subMenu": [
{
"name": "Newsletter Subscribers"
}
]
}
]
}
]
How the JSON look like in Realtime Firebase
'Click the image'
datamodel.dart
class Menu {
String? name;
int? font;
List<Menu>? subMenu = [];
Menu({this.name, this.subMenu, this.font});
Menu.fromJson(Map<String, dynamic> json) {
font = json['font'];
name = json['name'];
if (json['subMenu'] != null) {
json['subMenu'].forEach((v) {
subMenu?.add(Menu.fromJson(v));
});
}
}
}
My goal is to build a multilevel list view in Flutter that reflexes iterative JSON structure. So, I implemented a method that returns List<Menu>, and then pass it to a Futurebuilder to build a multilevel list View.
The method.
final ref = FirebaseDatabase.instance.ref();
Future<List<Menu>> firebaseCalls(DatabaseReference ref) async {
final snapshot = await ref.child('Task').get();
final jsondata = snapshot.value as Map<String, dynamic>;
final list = json.decode(jsondata) as List<dynamic>; // Error Location
return list.map((e) => Menu.fromJson(e)).toList();
}
and I got the following
The Error
error: The argument type 'Map<String, dynamic>' can't be assigned to the parameter type 'String'. (argument_type_not_assignable at [flutter_multilevel_list_from_json] lib\main.dart:28)
tried to change the list type to List<dynamic> but still give me an error.
json.decode() takes a String as input, and you are passing a Map<String,dynamic> into it.
That is your problem, not that you are trying to cast it to a List<dynamic>
May be this will be helpful (jsondata as List).map((e) => Menu.fromJson(e)).toList();
My project is about a shopping application build with Spring boot. When I get the shopping cart from the endpoint. It will return JSON like this
{
"shoppingCartCode": 2,
"productDetailList": [
{
"productDetailCode": 5,
"price": 21000.0,
"dateManufacture": "2021-09-23",
"quantity": 10,
"colorName": "Pink",
"warranty": 2,
"product": {
"prodCode": 2,
"prodName": "Z Flod 10",
"description": "Z Flod 10 Flippable then Break up",
"brand": {
"brandName": "Samsung",
"imageList": []
},
"shop": {
"shopCode": 5,
"shopName": "Montri Phone",
"shopDescription": "Strict security",
"type": "SELLER",
"imageList": []
}
},
"imageList": [
{
"imageName": "i-agree.png"
},
{
"imageName": "i-agree1.png"
},
{
"imageName": "i-agree2.png"
},
{
"imageName": "i-agree3.png"
}
]
}
]
}
I want to manipulate the imageList to like this
"imageList": ["i-agree.png","i-agree1.png","i-agree2.png","i-agree3.png"]
Is there any way to manipulate JSON before response?
or it might need POJO to wrap it up before response again?
You can achieve this with a custom serializer as follows:
public class ImageListConverter extends StdConverter<List<Image>, List<String>> {
#Override
public List<String> convert(List<Image> images) {
return images.stream().map(User::getImageName).collect(Collectors.toList());
}
}
Now you just need to annotate the imageList property:
public class ProductDetail {
#JsonSerialize(converter = ImageListConverter.class)
List<Image> imageList;
}
The other option would be changing List<Image> to List<String> and do the conversion when creating ProductDetail. It really depends on how you use ProductDetail elsewhere.
I have a json like this, which i am getting in the response from http call
{
"offset": 0,
"limit": 50,
"objects": [
{
"id": "59118fb6e4b0168ec4b56692",
"modifiedDate": 1494323126886,
"requestedIds": null,
"mergedIds": [],
"properties": {
"name": [
{
"value": "Abhimanyu",
"metadata": {}
}
],
"company": [],
"title": [],
"email": [
{
"value": "absinghrathore127#gmail.com",
"metadata": {}
}
]
},
"state": "ACTIVE"
},
{
"id": "590d5813e4b03a8336fa1642",
"modifiedDate": 1494046739619,
"requestedIds": null,
"mergedIds": [],
"properties": {
"name": [
{
"value": "Tim Archer",
"metadata": {}
}
],
"company": [],
"title": [],
"email": [
{
"value": "tim#avocado.com",
"metadata": {}
}
]
},
"state": "ACTIVE"
}
],
"size": 2
}
and i am able to get objects from json via this following code :
String s = res.getBody();
Map<String,Object> jsonMap = (Map<String, Object>)JSON.deserializeUntyped(s);
String jsonSubset = JSON.serialize(jsonMap.get('objects'));
What i need is the value of name and email in some variable.
Please help me out in this!!
This is going to be a tedious task but once you've classified your all data into appropriate Wrapper classes then it's fairly simple and easy to maintain.
First thing is to define your MainWrapper class. This will contain all the at it's own level. If it has any Object as key-pair then we need to make sure to include it as a List<>. So This is how your MainWrapper should be:
public class MainWrapper {
Integer offset; // Singleton variable
Integer limits; // Singleton variable
List<ObjectsWrapper> objects; // Collection variable since it starts with [],
Integer size; // Singleton variable
}
Since you've array of objects in JSON that's why I've included it as a List in MainWrapper. Now it's time to define ObjectsWrapper. Below is wrapper defined for the same.
public class ObjectsWrapper {
String id;
String modifieddate;
String requestedIds;
PropertyWrapper properties;
}
Since there is only on properties associated with objects that's why it's a non-collection type. Below is representation of properties.
public class PropertyWrapper {
List<NameWrapper> name;
List<String> company;
List<String> title;
List<EmailWrapper> email;
String state;
}
public class NameWrapper {
String name;
String metadata;
}
I guess now you've a fair idea of how to organize data of JSON into various wrapper class. Once you're done with this, simply deserialize the JSON into MainWrapper class and access it.
For example:
MainWrapper mainJSONWrapper = (MainWrapper) JSON.deserialize(JSON,MainWrapper.class);
List<ObjectsWrapper> objectsLst = mainJSONWrapper.objects;
for(ObjectsWrapper obj:objectsLst) {
List<NameWrapper> lstNameWrapper = obj.properties;
for(NameWrapper nameObj:NameWrapper) {
System.debug('Name:'+nameObj.name);
System.debug('metadata:'+nameObj.metadata);
}
}
Above code is not tested but yes, it will give idea how you should deserialize JSON in appropriate manner.
Also go through this answer..How to deserialize a JSON String to Apex
I am getting the following exception after writing the below code.
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Root name 'Filing' does not match expected ('List') for type [collection type; class java.util.List, contains [simple type, class MasMonthlyReportDetail]]
JSON Object
{
"Filing":
[
{
"periodInfo":
{
"date": "06-05-2013",
"year": "2015",
"Month": "January"
},
"employerInfo":
{
"name": "Y",
"place": "Y",
"country": "N",
},
"employeeInfo":
[
{
"name": "785-23-0370",
"dob": "05/25/1952",
}
],
"messages":
[
{
"defaultMessage" : "xx",
"messageType" : "yy",
"messageCode" : "102"
}
]
},
{
"periodInfo":
{
"date": "06-05-2013",
"year": "2015",
"Month": "January"
},
"employerInfo":
{
"name": "Y",
"place": "Y",
"country": "N",
},
"employeeInfo":
[
{
"name": "785-23-0370",
"dob": "05/25/1952",
}
],
"messages":
[
{
"defaultMessage" : "xx",
"messageType" : "yy",
"messageCode" : "102"
}
]
}
]
}
Main Class
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
List<MasMonthlyReportDetail> lcd = objectMapper.readValue(new File(filePath),new TypeReference<List<MasMonthlyReportDetail>>(){});
MasMonthlyReportDetail.java
#JsonRootName(value="Filing")
public class MasMonthlyReportDetail {
private PeriodInfo periodInfo;
private EmployerInfo employerInfo;
List<EmployeeInfo> employeeInfo;
List<Messages> messages;
public PeriodInfo getPeriodInfo() {
return periodInfo;
}
public void setPeriodInfo(PeriodInfo periodInfo) {
this.periodInfo = periodInfo;
}
public EmployerInfo getEmployerInfo() {
return employerInfo;
}
public void setEmployerInfo(EmployerInfo employerInfo) {
this.employerInfo = employerInfo;
}
public List<EmployeeInfo> getEmployeeInfo() {
return employeeInfo;
}
public void setEmployeeInfo(List<EmployeeInfo> employeeInfo) {
this.employeeInfo = employeeInfo;
}
public List<Messages> getMessages() {
return messages;
}
public void setMessages(List<Messages> messages) {
this.messages = messages;
}
}
I made the following changes and the code worked for me.
Main Class:
InputStream inputStream = resource.getInputStream();
ObjectMapper objectMapper = new ObjectMapper();
MasMonthlyReportDetailHolder masMonthlyReportDetailHolder = objectMapper.readValue(inputStream, MasMonthlyReportDetailHolder.class);
List<MasMonthlyReportDetail> masMonthlyReportDetail = masMonthlyReportDetailHolder.getMasMonthlyReportDetail();
MasMonthlyReportDetailHolder class:
public class MasMonthlyReportDetailHolder {
private List<MasMonthlyReportDetail> masMonthlyReportDetail;
#JsonProperty("Filing")
public List<MasMonthlyReportDetail> getMasMonthlyReportDetail() {
return masMonthlyReportDetail;
}
public void setMasMonthlyReportDetail(
List<MasMonthlyReportDetail> masMonthlyReportDetail) {
this.masMonthlyReportDetail = masMonthlyReportDetail;
}
}
Adding #JsonProperty("Filing") is the key to avoid this issue. In case of any other procedure, do let me know.
have u tried this ?
jacksonObjectMapper.reader(MasMonthlyReportDetail.class).withRootName("Filing").readValue(jsonAsString);
I have data that looks like this:
{
"status": "success",
"data": {
"irrelevant": {
"serialNumber": "XYZ",
"version": "4.6"
},
"data": {
"lib": {
"files": [
"data1",
"data2",
"data3",
"data4"
],
"another file": [
"file.jar",
"lib.jar"
],
"dirs": []
},
"jvm": {
"maxHeap": 10,
"maxPermSize": "12"
},
"serverId": "134",
"version": "2.3"
}
}
}
Here is the function I'm using to prettify the JSON data:
public static String stringify(Object o, int space) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(o);
} catch (Exception e) {
return null;
}
}
I am using the Jackson JSON Processor to format JSON data into a String.
For some reason the JSON format is not in the format that I need. When passing the data to that function, the format I'm getting is this:
{
"status": "success",
"data": {
"irrelevant": {
"serialNumber": "XYZ",
"version": "4.6"
},
"another data": {
"lib": {
"files": [ "data1", "data2", "data3", "data4" ],
"another file": [ "file.jar", "lib.jar" ],
"dirs": []
},
"jvm": {
"maxHeap": 10,
"maxPermSize": "12"
},
"serverId": "134",
"version": "2.3"
}
}
}
As you can see under the "another data" object, the arrays are displayed as one whole line instead of a new line for each item in the array. I'm not sure how to modify my stringify function for it to format the JSON data correctly.
You should check how DefaultPrettyPrinter looks like. Really interesting in this class is the _arrayIndenter property. The default value for this property is FixedSpaceIndenter class. You should change it with Lf2SpacesIndenter class.
Your method should looks like this:
public static String stringify(Object o) {
try {
ObjectMapper mapper = new ObjectMapper();
DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
printer.indentArraysWith(new Lf2SpacesIndenter());
return mapper.writer(printer).writeValueAsString(o);
} catch (Exception e) {
return null;
}
}
I don't have enough reputation to add the comment, but referring to the above answer Lf2SpacesIndenter is removed from the newer Jackson's API (2.7 and up), so instead use:
printer.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE);
Source of the solution