I am trying to parse json to java.
I have the following string that is valid json according to jsonlint.com
private final static String LOC_JSON =
"["
+"{"
+" \"lat1\": 39.737567,"
+" \"lat2\": 32.7801399,"
+" \"long1\": -104.98471790000002,"
+" \"long2\": -96.80045109999998"
+"},"
+" ["
+" {"
+" \"lat\": {"
+" \"b\": 38.88368709500021,"
+" \"d\": 40.620468491667026"
+" },"
+" \"long\": {"
+" \"b\": -105.75306170749764,"
+" \"d\": -104.675854661387"
+" }"
+" }"
+" ]"
+"]";
I am trying to parse it into an object and I get the following error.
"Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2"
Gson gson = new Gson();
BoxSearch b = gson.fromJson( LOC_JSON, BoxSearch.class );
BoxSearch consists of this.
private Number lat1;
private Number lat2;
private Number long1;
private Number long2;
private Boxes[] boxes;
Boxes is a Latitude object and a Longitude object which are both defined identical.
private String b;
private String d;
I can parse the higher level attributes (lat1,lat2,long1 and long2) into a more simple BoxSearch object that only has those 4 attributes. The trouble comes when the json and the object are more complex. Is it even possible to do what I am trying?
I hope I have provided enough information to get some help. I would be happy to provide more info or even a test project if need be. I am running this as a junit test.
Thanks.
Gson gson = new Gson();
gson.fromJson(jsonStr,YourClass.class);
very easy.
The reason for the error is that your JSON at the top level is an array, not an object. That is covered by GSON throwing "Expected BEGIN_OBJECT but was BEGIN_ARRAY"?.
However, the solution there won't work for your JSON because you have an array of mixed types (an object and an array) rather than an array of a single type of object. For that you're going to have to write a custom deserializer (See The section of the Gson user's guide that covers this) or use Gson's JsonParser class directly and extract the data from the parse tree.
Edit from comments above:
If you're the one creating the JSON, it looks like what you want is an array of BoxSearch objects?
Based on your Java BoxSearch class, you'd need JSON structured like:
[
{
"lat1" : 39.737567,
"lat2" : 32.7801399,
"long1" : -104.98471790000002,
"long2" : -96.80045109999998,
"boxes" : [
{
"lat": {
"b": 38.88368709500021,
"d": 40.620468491667026
},
"long": {
"b": -105.75306170749764,
"d": -104.675854661387
}
}
]
}
]
However, the way you have Boxes class defined won't work for that. (Did you mean to have an array of them?). As-is it would need to look like:
class Boxes {
Box lat;
#SerializedName("long")
Box lon;
}
class Box {
String b;
String d;
}
Now you have an array containing one type of object (BoxSearch) which you could deserialize with:
Type collectionType = new TypeToken<Collection<BoxSearch>>(){}.getType();
Collection<BoxSearch> boxSearchCollection = gson.fromJson(json, collectionType);
If you really don't need an array of these, get rid of the outer array and simply do:
gson.fromJson(json, BoxSearch.class);
Related
I have a JSON with this structure:
{
"firstProperty": true,
"thisIsAString": "hi",
"myList": [
{"myBool": true},
{"myBool": false, "otherfield": true}
]
}
The myList is a List<MyClass> in the target class.
This MyClass only has the myBool field which causes the first element of the array to properly deserialize but unfortunately deserializing the second element causes it to fail with the error message Unknown property 'myBool' for class my.package.MyClass at JSON path $.otherfield.
Is there any way to just ignore fields in the JSON that don't exist in the target class of the deserialization? Maybe it is because of nested objects?
I already tried to add a custom type adapter like seen here but it didn't even call the method (the target class is a record which is why i have to use the third party library com.github.Marcono1234:gson-record-type-adapter-factory to deserialize it)
AFAIK, Gson will ignore unknown fields automatically while deserialization. So, I assume that you have already created these 2 classes which look like:
public class MyClass {
private Boolean myBool;
// getter, setter and toString
}
public class MyResult {
private Boolean firstProperty;
private String thisIsAString;
List<MyClass> myList;
// getter, setter and toString
}
Then you can serialize your JSON string as follows:
String yourJsonStr = "" +
"{\n" +
" \"firstProperty\": true,\n" +
" \"thisIsAString\": \"hi\",\n" +
" \"myList\": [\n" +
" {\"myBool\": true},\n" +
" {\"myBool\": false, \"otherfield\": true}\n" +
" ]\n" +
"}";
Gson gson = new Gson();
MyResult myResult = gson.fromJson(yourJsonStr, MyResult.class);
System.out.println(myResult.toString());
Console output:
MyResult{firstProperty=true, thisIsAString='hi', myList=[MyClass{myBool=true}, MyClass{myBool=false}]}
I found the issue, the third party library I use to deserialize into records has a TypeAdapterFactory which has a option to ignore unknown properties which is set to false per default.
Turning this option on produces the expected output.
I am using Java.
I have a string that I have converted to a JSON Object.
I want to extract the value of one of the Keys.
At the moment I am using this code:
String imageId = myJsonObject.getJSONObject("meta")
.getJSONObject("verification")
.getJSONObject("derivedData")
.getJSONArray("images")
.getJSONObject(0)
.getString("imageID");
This code works but surely there must be an easier way. In javascript I could access the value simply by writing this:
myJsonObject.meta.verification.derivedData.images[0].imageId
You may need to install library such as JsonPath to help you select values from a JSON object
An example to help understand better.
You can use external library Gson
Gson gson=new Gson();
/*You can convert to your DTO as well */
Map<Object,Object> map = gson.from(myJsonObject,Map.class);
Other way is using objectmapper example of fasterxml.
ObjectMapper objectMapper=new ObjectMapper();
/*You can convert to your DTO as well */
objectMapper.readValue(data, Map.class);
Try JsonNode by below step
String imageId= jsonNode.
findPath("meta")
.findPath("verification")
.findPath("derivedData")
.findPath("images")
.get (0).findPath ("imageID").asText ();
You need to use the 'Java API for JSON Binding' JSON-B instead of JSON-P. Using JSON-B you can serialize and deserialize between Java objects and data streams and access values of objects POJO style (similar to what you expect).
API details can be found here
A quick start tutorial can be found here and at many website only google search away..
I have created a small class for this purpose which can basically get value from json using a path only used google.gson
https://github.com/izeryab/JsonParser
Here is how to use this for getting nested value from json:
public class Main {
public static void main(String[] args) {
String json = "{\"data\":[{\"stuff\":[\n" + " { \"onetype\":[\n"
+ " {\"id\":1,\"name\":\"John Doe\"},\n" + " {\"id\":2,\"name\":\"Don Joeh\"}\n"
+ " ]},\n" + " {\"othertype\":[\n" + " {\"id\":2,\"company\":\"ACME\"}\n" + " ]}]\n"
+ "},{\"otherstuff\":[\n" + " {\"thing\":\n" + " [[1,42],[2,2]]\n" + " }]\n" + "}]}";
String name = JsonUtil.getJsonElementFromJsonStringUsingPath("data>0>stuff>0>onetype>0>name", json, ">").getAsString();
int id= JsonUtil.getJsonElementFromJsonStringUsingPath("data>0>stuff>0>onetype>0>id",json,">").getAsInt();
System.out.println("id : "+id);
System.out.println("name : "+name);
}
}
Corresponding JAVA DOCS:
https://izeryab.github.io/JsonParser/JsonUtil.html
You can use GSon, I've used it before (see below)
// Convert to a JSON object to print data
JsonParser jp = new JsonParser(); //from gson
JsonElement root = jp.parse(new InputStreamReader((InputStream) request.getContent())); //Convert the input stream to a json element
JsonObject rootobj = root.getAsJsonObject(); //May be an array, may be an object.
JsonArray jsonDataArray = rootobj.getAsJsonArray("data");
JsonPrimitive totalJson = rootobj.getAsJsonPrimitive("total");
JsonPrimitive nextJson = rootobj.getAsJsonPrimitive("next");
I'm working in Java, and I have some JSON that is kinda like this:
{
"objectList" : [{...}, {...}, ...],
"metadata" : {...}
}
What I want to do is get the list and objects as JSON strings. So basically, I want to deserialize this JSON into an object like this:
{
"objectList" : "[{...}, {...}, ...]",
"metadata" : "{...}"
}
So I can do further processing on those strings.
What's the best way to do this?
I'm hesitant to try to use String parsing to extract the data I need since the values inside those objects may affect how it's being parsed.
If I were you, I'd use some JSON-parsing library (such as Gson) to turn your JSON into a JsonObject. You can then simply get the value of objectList as a String using JsonObject#getAsString:
String json = "{\n" +
" \"objectList\" : \"[{...}, {...}, ...]\", \n" +
" \"metadata\" : \"{...}\" \n" +
"}";
JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class);
System.out.println(jsonObject.get("objectList").getAsString());
Output:
[{...}, {...}, ...]
I have a DTO class like this:
package stbet.model.dto.db;
public class UKDashboardEventDTO implements Serializable{
private Long eventId;
private String meetingCode;
private String meetingName;
private String eventTime;
private String eventCode;
private String settleStatus;
private String category;
//getters and setters here:
#Override
public String toString() {
return "eventList{" + "eventId=" + eventId + ", meetingCode=" + meetingCode + ", meetingName=" + meetingName
+ "eventTime=" + eventTime + ", eventCode=" + eventCode + ", settleStatus=" + settleStatus
+ ", category=" + category + '}';
}
}
and I do some query stuff and create a java List of above DTO type.
for(Event ev : eventList){
dto = new UKDashboardEventDTO();
// some stuff
dto.setEventCode(ev.getEventCode());
dto.setEventId(ev.getId());
dto.setEventTime(ev.getEventTime());
dto.setMeetingName(ev.getMeeting().getMeetingName());
dto.setMeetingCode(ev.getMeeting().getMeetingCode());
eventDTOList.add(dto);
}
Then I add this list into a Hashmap and covert it into a JSON object like this:
Map map = new HashMap();
map.put("eventList",eventDTOList);
now convert into the json:
JSONObject obj = new JSONObject();
try {
obj.put("eventMap", map);
} catch (JSONException ex) {
}
out.println(obj);
out.flush();
out.close();
but when I get this object from client side, I am getting the dto package/object names list when parse or stringify the output instead of the proper dto values I passed from Java. What I get is this:
"{"eventMap":{"eventList":["stbet.model.dto.db.UKDashboardEventDTO#617538bb","stbet.model.dto.db.UKDashboardEventDTO#56dfaef9","stbet.model.dto.db.UKDashboardEventDTO#775889fd","stbet.model.dto.db.UKDashboardEventDTO#55cb7e41","stbet.model.dto.db.UKDashboardEventDTO#22ce0968","stbet.model.dto.db.UKDashboardEventDTO#4cb9cb2"]}}"
can you please let me know how to get the dto values I set from Java to client side json without java package name as above.
Firstly, you're using both JSON and GSON libraries, JSONException exists in JSON one and Expose annotation is in GSON. Please make sure you don't mix them as I won't work as intended.
Secondly, from Expose documentation
An annotation that indicates this member should be exposed for JSON serialization or deserialization.
This annotation has no effect unless you build Gson with a GsonBuilder and invoke GsonBuilder.excludeFieldsWithoutExposeAnnotation() method.
You should Override the toString field on the DTO, to print out all the individual field values.
This toString will be called when you do out.println(obj);
eg.
toString() {
// this method should list out all the attributes.
}
You should be using GSONBuilder to create the gson. Examples:
Gson: How to exclude specific fields from Serialization without annotations
Gson doesn't parse an exposed field
Here is a post on using GSON also
How to expose a method using GSon?
Finally I could fix it with your suggestions #Trynkiewicz Mariusz and #Paul John.
What I did was:
1. remove #Expose annotation
2. overridden the toString(){...} method.
3. remove the map implementation and used a List.
4. used gson.toJson(eventList);
this solved the issue and the output now is like :
[{
"eventId":167804,
"meetingCode":"V5PGB",
"meetingName":"SprintValley",
"eventTime":"15:38:00",
"eventCode":"10:08:00",
"category":"HR"
},
{
"eventId":167805,
"meetingCode":"V5PGB",
"meetingName":"SprintValley",
"eventTime":"15:50:00",
"eventCode":"10:20:00",
"category":"HR"
},..]
Thanks again guys...
I have been trying, and struggling, to parse arrays contained in a JSON file, into a Java ArrayList. Could I please have some advise on how to proceed with this? Please find an example JSON Array below:
[
{
"id": "USER_ID_HERE",
"dateTime": "DATE_TIME_HERE",
"message": "WRITE_SOMETHING_MEANINGFUL_HERE",
"latitude": 27.99999
"longitude": 26.33333333
}
]
My current Java code can be found below - how can I parse in the array from the JSON file?
public class ParseJSON {
ArrayList <Tweet> = new ArrayList <Tweet>();
class Tweet{
public String id;
public String message;
public String dateTime;
public double latitude;
public double longitude;
}
JSONObject js = new JSONObject("tweets");
JSONArray jsarray = js.getJSONArray("tweets");
int size = jsarray.length();
for (int i = 0; i < size; i++)
{
JSONObject tweet = jsarray.getJSONObject(i);
System.out.println("tweet: " + tweet.getString("id"));
System.out.println("tweet: " + tweet.getString("message"));
System.out.println("tweet: " + tweet.getString("dateTime"));
System.out.println("tweet: " + tweet.getDouble("latitude"));
System.out.println("tweet: " + tweet.getDouble("longitude"));
}
t = new tweet( tweet.getString("id")) & ( tweet.getString("message")) & ( tweet.getString("datetime")) & ( tweet.getDouble("latitude")) & ( tweet.getDouble("longitude"));
Tweet.list.add(t);
}
}
Thank you in advance for any advice.
You seem to be pretty close to the required functionality, some issues though:
Firstly, the code you want to execute is not in a method. Try to add a "main" method to your ParseJSON class.
Your Tweet class doesn't have a custom constructor, so you won't be able to create Tweet objects and populate their attributes with a constructor as you attempt to do further down.
Your ArrayList<Tweet> member variable doesn't have an identifier.
For:
t = new tweet( tweet.getString("id")) & ( tweet.getString("message")) & ( tweet.getString("datetime")) & ( tweet.getDouble("latitude")) & ( tweet.getDouble("longitude"));
You want to do this for each element of the JSON array, so move the line inside your for loop. Also, the parameters should be separated by a comma, not an ampersand. You should also use a capital T for new Tweet (to refer to the constructor you should have created).
For:
Tweet.list.add(t);
This currently expects list to be a (static) member of Tweet. Try changing this to access the name you should have given to your ArrayList. This line should also be inside the for loop for the same reason as above.