I have the following Item class:
public class Item {
public Object item;
}
I am inserting a JSON into this object using GSON.
tmp =
{
"_id": {
"$oid": "5076371389d22e8906000000"
},
"item": {
"values": [
{
"value1": [
4958,
3787,
344
],
"value2": [
4,
13,
23
]
}
],
"name": "item1"
}
}
Java bit:
Item item = new Item();
Gson g = new Gson();
it = g.fromJson(tmp.toString(), Item.class);
it.item becomes a StringMap type (http://code.google.com/p/google-gson/source/browse/trunk/gson/src/main/java/com/google/gson/internal/StringMap.java?r=1131)
I now need to access the sub-objects within this object.
I can use the overridden toString function this type has which prints all objects within this object. But how would I be able to navigate through it?
P.S. The reason I put everything into an object datatype not a structured class is that the JSON structure varies each time, so I can't really have a class schema.
Any suggestions?
You should create an object structure that reflects the JSON instead (since this is what you're trying to do anyway). For your example, you could use this:
public class MyObject {
private Item item;
private String _id;
// getters, setters, etc.
}
public class Item {
private List<Value> values;
private String name;
// getters, setters, etc.
}
public class Value {
private List<Integer> values1;
private List<Integer> values2;
// getters, setters, etc.
}
Then pass MyObject.class to Gson:
MyObject myObj = g.fromJson(tmp.toString(), MyObject.class);
You can get the lists in values like so:
List<Integer> values1 = myObj.getItem().getValues().get(0).getValues1();
List<Integer> values2 = myObj.getItem().getValues().get(0).getValues2();
Try that and see if it works.
Also, you should check out my answer to a similar question here, specifically the part at the end about how to write an object structure for Gson based on some JSON object.
You can always create a constructor for the custom object that uses reflection and takes the StringMap
public MyObject(StringMap sm){
Iterator it = sm.entrySet().iterator();
while(it.hasNext()){
Entry pairs = (Entry)it.next();
Class<?> c = this.getClass();
try {
Field value = c.getDeclaredField((String) pairs.getKey());
value.set(this, pairs.getValue());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Related
I have multiple JSON files, but they all look similar to this one (some much longer):
{
"$id": "http://example.com/myURI.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"description": "Sample Procedure schema.",
"properties": {
"prop1": {
"description": "",
"type": "string"
},
"prop2": {
"description": "",
"type": "number"
}
"prop3": {
"description": "",
"type": "string"
}
}
}
I want to extract the names (ex. "prop1","prop2") along with their types (ex. "string,"number") and format it to look something like the following:
public static class Whatever {
#JsonProperty
public String prop1;
#JsonProperty
public Integer prop2;
#JsonProperty
public String prop3;
public Whatever() {}
public Whatever(String prop1, Integer prop2, String prop3){
this(prop1, prop2, prop3);
}
}
I've never used Java before so I'm not sure where to begin in creating this script. Mainly I'm concerned with how I will iterate through the json object.
I would Approach this this way:
Create a main class that holds all the information of the JSON and a Secondary class that keeps the information of the prop properties of the JSON:
public class MainJsonObject
{
private int $id;
private int $schema;
// All the other objects that you find relevant...
private List<SecondaryJsonObject> propsList = new ArrayList<>(); // This will keep all your other props with description and type
// Getter and setter, do not forget them as they are needed by the JSON library!!
}
public class SecondaryJsonObject
{
private String description;
private String type;
// Getter and setter, do not forget them !!
}
You could iterate through your JSON Object this way:
First of all include the JSON Library in your project.
Then iterate through your JSON like this:
JSONObject jsonObject = new JSONObject(jsonString);
MainJsonObject mjo = new MainJsonObject();
mjo.set$id(jsonObject.getInt("$id")); // Do this for all other "normal" attributes
// Then we start with your properties array and iterate through it this way:
JSONArray jsonArrayWithProps = jsonObject.getJSONArray("properties");
for(int i = 0 ; i < jsonArrayWithProps.length(); i++)
{
JSONObject propJsonObject = jsonArrayWithProps.getJSONObject(i); // We get the prop object
SecondaryJsonObject sjo = new SecondaryJsonObject();
sjo.setDescription(propJsonObject.getString("description"));
sjo.setTyoe(propJsonObject.getString("type"));
mjo.getPropsList().add(sjo); // We fill our main object's list.
}
I am needing to parse JSON data coming in from an outside source. The problem is sometimes and array of data is sent in and sometimes it come in as a single object, but the array and the single object have the same name.
{
"OuterObject": {
"Names":[
{
"name": "John Doe"
},
{
"name": "William Watson"
}
]
}
}
But when the JSON array has only one element, it looks like this:
{
"OuterObject": {
"Names": {
"name": "John Doe"
}
}
}
My application needs to be able to handle either one of these, but not both at the same time.
This is what my Json parsed class looks like:
#JsonRootName("OuterObject")
public class OuterObject {
#JsonProperty("Names")
private Names names;
#JsonProperty("Names")
private List<Names> namesList;
public Names getNames() {
return names;
}
public void setNames(Names names) {
this.names = names;
}
public List<Names> getNamesList() {
return namesList;
}
public void setNamesList(List<Names> namesList) {
this.namesList = namesList;
}
}
However, it doesn't look like it will work to have the same json property name for both the list and the single object. It also doesn't appear to just use an array and have the single json object parse into the list. Does anyone know of any ways that my application can handle both json arrays and single json objects when the arrays and the objects have the same name?
You just need to use a single field of type List<Names>, and activate the feature ACCEPT_SINGLE_VALUE_AS_ARRAY
YourClass result = mapper.reader(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
.forType(YourClass.class)
.readValue(json);
I have used following method for convert JSONArray, if it is only one JSONObject.
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
private JSONArray getJSONArray(JSONObject json, String field) {
JSONArray array;
if(json.get(field) instanceof JSONObject){
array = new JSONArray();
array.add(json.get(field));
}else{
array = json.getJSONArray(field);
}
return array;
}
Convert your json to Map then use your code to get the desired result.
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map = mapper.convertValue(json, Map.class);
or better
Map<String, Object> map = mapper.convertValue(json, new TypeReference<Map<String, Object>>() {});
I am trying to parse a json string to java object but i am not sure on the object hierarchy.
below is the json string
{
"TABLE_Detail":{
"1":{
"TABLE":"table1",
"RUN_DATE":"20170313",
"SEQ_NUM":"123",
"START_TIME":"20170313133144",
"END_TIME":"20170313133655"
},
"2":{
"TABLE":"table2",
"RUN_DATE":"20170313",
"SEQ_NUM":"123",
"START_TIME":"20170313133142",
"END_TIME":"20170313133723"
}
}
}
Here the number 1, 2 are dynamic and can go up to any number, I tried to create a outer object and have a Map of type key String and value as object TableData. The map having variable name TABLE_Detail. but the TableData object is always null. TableData object has all the variables.
Please help me on how to convert this json string to object.
Change 1 to table1 and 2 to table2:
public class TableDetails {
private TableData table1;
private TableData table2;
public TableDetails(){
}
// getter and setter
}
And if modify json format to "Koen Van Looveren" mentioned:
public class TableDetails {
List<TableData> tables;
public TableDetails() {
}
// getter and setter
}
The table class:
Table.java:
public class TableData {
private String table;
private String run_date;
private String seq_num;
private String start_time;
private String end_time;
public TableData() {
}
// getter and setter
}
you have two choice for such painfully json structure when using Gson.
using Gson parsing json as Map and write some class access returned Map.this mode works fine for access data only!
//usage
TableDetails details=new TableDetails(gson.fromJson(json, Map.class));
//classes
class TableDetails {
private Map<String, Map> context;
public TableDetails(Map root) {
this.context = (Map<String, Map>) root.get("TABLE_Detail");
}
public int size() {
return context.size();
}
public Table get(String key) {
return new Table(context.get(key));
}
}
class Table {
private Map context;
public Table(Map context) {
this.context = context;
}
public String getName() {
return get("TABLE");
}
private <T> T get(String name) {
return (T) context.get(name);
}
...
}
write your own Gson TypeAdapter,but this way may be more complex.if you interesting on write custom TypeAdapter there is a demo that I written for extract json root.gson-enclosing-plugin
You can try deserialize it into a Map<String, Map<String, TableData>>. The reason why Map<String, TableData> doesn't work it that the pesudo-array is wrapped in another object.
The following example converts a response into a List<TableData>:
public List<TableData> deserialize(String json) {
return Gson().<Map<String, Map<String, TableData>>>fromJson(json, new TypeToken<Map<String, Map<String, TableData>>>(){}.getType())
.values().iterator().next()
.entrySet().stream()
.sorted(Comparator.comparingInt(e -> Integer.parseInt(e.getKey())))
.map(Map.Entry::getValue)
.collect(Collectors.toList());
}
I was in a search for the solution, and i came across one of the site where the solution worked. i wanted to credit the below site. Thanks for all the support.
I am able to map the dynamic value 1, 2 as map keys and values are mapped correspondingly to the TableData object properties using #SerializedName gson annootation.
http://findnerd.com/list/view/Parse-Json-Object-with-dynamic-keys-using-Gson-/24094/
When using an array in json you need to use [ for opening and ] for closing
{
"TABLE_Detail": [
{
"TABLE": "table1",
"RUN_DATE": "20170313",
"SEQ_NUM": "123",
"START_TIME": "20170313133144",
"END_TIME": "20170313133655"
},
{
"TABLE": "table2",
"RUN_DATE": "20170313",
"SEQ_NUM": "123",
"START_TIME": "20170313133142",
"END_TIME": "20170313133723"
}
]
}
I need to make a Builder class in which I need to have below fields so when I populate those fields in my Builder class and then if I call toJson method on it which I need to create as well, then it should make json structure like as shown below:
{
"id": "hello",
"type": "process",
"makers": {
"typesAndCount": {
"abc": 4,
"def": 3,
"pqr": 2
}
}
}
Key in my above JSON is fixed always only the values will change. But in typesAndCount field I have three different keys abc, def and pqr. Sometimes I will have one key there or two keys or all the keys. So stuff in typesAndCount key can change depending on what's being passed. Below is also possible case.
{
"id": "hello",
"type": "process",
"makers": {
"typesAndCount": {
"abc": 4,
"def": 3,
}
}
}
I started with below code in my Builder class but not sure how should I proceed further.
public class Key {
private final String id;
private final String type;
// confuse now
}
I just want to populate data in my class and then call some method it can be toJson to make string in above JSON format.
User Builder pattern for fluent configure your data builder. E.g.
class Builder {
private final String id;
private final String type;
private Map<String, Integer> map = new HashMap<>();
// mandatory fields are always passed through constructor
Builder(String id, String type) {
this.id = id;
this.type = type;
}
Builder typeAndCount(String type, int count) {
map.put(type, count);
return this;
}
JsonObject toJson() {
JsonObjectBuilder internal = null;
if (!map.isEmpty()) {
internal = Json.createObjectBuilder();
for (Map.Entry<String, Integer> e: map.entrySet()) {
internal.add(e.getKey(), e.getValue());
}
}
// mandatory fields
JsonObjectBuilder ob = Json.createObjectBuilder()
.add("id", id)
.add("type", type);
if (internal != null) {
ob.add("makers", Json.createObjectBuilder().add("typesAndCount", internal));
}
return ob.build();
}
public static void main(String[] args) {
Builder b = new Builder("id_value", "type_value")
.typeAndCount("abs", 1)
.typeAndCount("rty", 2);
String result = b.toJson().toString();
System.out.println(result);
}
}
As you can see you can call typeAndCount as many times as you need or even don't call it at all. toJson method handles this without any problem.
UPDATE: The output for example in method main is
{"id":"id_value","type":"type_value","makers":{"typesAndCount":{"abs":1,"rty":2}}}
UPDATE 2: the builder without 'typeAndCount` method call at all will produce this output
{"id":"id_value","type":"type_value"}
I have a json string like this:
{
"d": {
"results": [
{
"__metadata": {
"uri": "http://localhost:2000",
"key_fields": "Accountnum",
"rows_affected": 0,
"last_autoinc": 0
},
"Accountnum": "9999999",
"workphone": null,
"name": "Smith",
"address": "33 Main St",
"city": "Anytown",
"state": "FL",
"zip": "33333",
}
]
}
}
and I tried to deserialize it according to diffrent questions here on stackoverflow, but I can't get it right.
Here is what I did I created a class, I only need the accountnum and name.
public class Result {
#SerializedName("Accountnum")
public String accountnumStr;
#SerializedName("name")
public String nameStr;
}
I have a string with the json myresult.
Gson gson = new Gson();
Result result = gson.fromJson(myresult,Result.class);
myName.setText(result.nameStr);
I receive an empty string.
Thanks
Since there is a object holding the result object your trying to create, you have make the result class an inner class. You're Result class would have to look like this:
public class ResultParent {
public class Result {
#SerializedName("Accountnum")
public String accountnumStr;
#SerializedName("name")
public String nameStr;
}
}
If you visualize your JSON in terms of class objects then it will be no problem at all. Imagine that your root object contains a property named "d" of type "D". And type "D" contains a list of "results" of another type "Result". The result contains its properties as above. Here's the picture of it:
class RootObj {
D d;
}
class D {
List<Result> results;
}
class Result {
#SerializedName("Accountnum")
public String accountnumStr;
#SerializedName("name")
public String nameStr;
}
To get the objects from a JSON, you would do the following:
Gson g = new Gson();
RootObj ro = g.fromJson(jsonString, RootObj.class);