I have a map property:
private Map<String, Attribute> attributes = new HashMap<>();
Attribute object looks like this:
public class Attribute{
private String value;
private String name;
//with constructor setters and getters
}
How do I represent attributes Map object as JSON?
I am getting a JsonSyntaxException:
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY
when I'm trying to convert JSON object using fromJson() in the following code:
Attribute attribute = Gson().fromJson(jsonObect,Attribute.class)
My JSON object looks like this:
{
"attributes":[
{
"name":"some name",
"value":"some value"
}
]
}
it is easy to check:
Map<String,Attribute> attributes = new HashMap<>();
attributes.put("key_0", new Attribute("value_0", "name_0"));// I added constructor and getter/setter methods to class Attribute
attributes.put("key_1", new Attribute("value_1", "name_1"));
attributes.put("key_2", new Attribute("value_2", "name_2"));
//serialize using ObjectMapper
ObjectMapper mapper = new ObjectMapper();
var s = mapper.writeValueAsString(attributes);
System.out.println(s);
output:
{
"key_2":{
"value":"value_2",
"name":"name_2"
},
"key_1":{
"value":"value_1",
"name":"name_1"
},
"key_0":{
"value":"value_0",
"name":"name_0"
}
}
I am getting: "Expected BEGIN_ARRAY but was BEGIN_OBJECT" error when I'm trying to convert JSON object using fromJson() in the following code:
Attribute attribute = Gson().fromJson(jsonObect,Attribute.class)
The following JSON object doesn't match either a single Attribute object or a map Map<String, Attribute>:
{
"attributes":[
{
"name":"some name",
"value":"some value"
}
]
}
Have a look carefully, the value mapped to the key "attributes" is a JSON-array.
Hence, you can parse it successfully into a map of type Map<String, List<Attribute>>
That's how it can be implemented using Gson.fromJson() and TypeToken (for more options, see this question):
public static void main(String[] args) {
String jsonStr = """
{
"attributes":[
{
"name":"some name",
"value":"some value"
}
]
}""";
Gson gson = new Gson();
Type mapStrByStr = new TypeToken<Map<String, List<Attribute>>>(){}.getType();
Map<String, List<Attribute>> map = gson.fromJson(jsonStr, mapStrByStr);
System.out.println(map);
}
}
public static class Attribute{
private String value;
private String name;
#Override
public String toString() {
return "Attribute{" +
"value='" + value + '\'' +
", name='" + name + '\'' +
'}';
}
}
Output:
{attributes=[Attribute{value='some value', name='some name'}]}
Related
i need to access the values of a Json, that its inside an Array, that its inside of a Json, the structure of the Json file its like this:
{
"Places": [
{
"id": 17,
"city": "Chicago",
"vehicle": "car"
},
{
"id": 13,
"city": "New York",
"vehicle": "plane",
}
]
}
i only need the values of "id", "city" and "vehicle"
im using the map function like this:
Gson gson = new Gson();
Map<String,String> userMap = gson.fromJson(contentoffile, Map.class);
for (Object value : userMap.values()) {
Map places= (Map) value;
int id = (int) (places.get("id"));
String city= (String) places.get("city");
String vehicle= (String) places.get("vehicle");
but i got the next error
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.util.Map
how i can acces the data?
btw, i can use other libraries for this, not only Map function
The structure you have is a JSON object that contains a JSON array places, I am not really sure what you are trying to achieve by using a Map<String, String>, you need to either create a Place POJO and parse accordingly OR just access it directly as a JsonObject:
Place.java
public class Place
{
private int id;
private String city;
private String vehicle;
public Place(int id, String city, String vehicle)
{
this.id = id;
this.city = city;
this.vehicle = vehicle;
}
// Setters & getters
}
public static void main(String[] args)
{
Gson gson = new Gson();
// Parse your file to a JsonObject
JsonObject jsonObject = gson.fromJson(contentoffile, JsonObject.class);
// Extract JsonArray (places) from JsonObject
JsonArray jsonArray = jsonObject.get("Places").getAsJsonArray();
Option 1: Converting into List<Place>:
// Convert JsonArray to a list of places
Type type = new TypeToken<List<Place>>() {}.getType();
List<Place> places = gson.fromJson(jsonArray, type);
//iterate over places
for (Place place : places)
{
int id = place.getId();
//etc..
}
}
Option 2: Iterating directly over JsonArray:
for (JsonElement jsonElement : jsonArray)
{
//This will represent a Place object
JsonObject curr = jsonElement.getAsJsonObject();
int id = curr.get("id").getAsInt();
String city = curr.get("city").getAsString();
String vehicle = curr.get("vehicle").getAsString();
}
Option 3: Create a wrapper class
public class PlaceWrapper
{
private List<Place> places;
//Const, setters, getters
}
public static void main(String[] args)
{
Gson gson = new Gson();
// Deserialize json
PlaceWrapper placeWrapper = gson.fromJson(contentoffile, PlaceWrapper.class);
// iterate over places
for (Place place : placeWrapper.getPlaces())
{
// do your thing
}
}
I am trying to deserialize the json into MyClass object but every time I get the exception though I am able to serialize the JSON object.
**com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token**
The json I am trying to deserialize is
{
"siteName": "avisports",
"csAssetTypes": [
"Content_C",
[
"name",
"description",
"subheadline",
"abstract",
"body",
"headline",
"subheadline",
"avi_content_title",
"avi_content_body",
"avi_content_headline",
"avi_content_abstract"
]
]
}
my Bean is something like
public class GlContentServerConfig{
private String siteName;
private Map<String, List<String>> csAssetTypes = new HashMap<String, List<String>>();
//getters ans setters
}
and my service method is
#Override
public GlContentServerConfig getConfiguredAttributes(String siteName, String assetType) throws Exception {
if (this.configMap == null) {
this.configMap = this.configDAO.getAllConfigs();
}
GlContentServerConfig config = new GlContentServerConfig();
config.setSiteName(siteName);
config.setCsAssetTypes(csService.getAssetTypeAttributeList(assetType));
GloballinkConfig obj = this.configMap.get(siteName);
if (obj != null) {
String jsonValue = obj.getGlConfigValue();
config=this.mapper.readValue(jsonValue, GlContentServerConfig.class); // error comes from this line
//List<GlContentServerConfig> glconfigList= this.mapper.readValue(jsonValue, new TypeReference<GlContentServerConfig>(){});
//List<GlContentServerConfig> glconfigList = this.mapper.readValue(jsonValue, this.mapper.getTypeFactory().constructCollectionType(List.class, GlContentServerConfig.class));
System.out.println("final : "+glconfigList.toString());
}
return config;
}
I have tried all most all of the permutations and combinations. Few of them are commented in the code.
I am unable to figure out the way to use Jackson. please help me out.
add #JsonProperty("csAssetTypes") to your Bean :
public class GlContentServerConfig{
private String siteName;
#JsonProperty("csAssetTypes")
private Map<String, List<String>> csAssetTypes = new HashMap<String, List<String>>();
//getters ans setters
}
I am trying to parse a JSON object like the following with GSON:
{
"key1":"someValue",
"key2":{
"anotherKey1":"212586425",
"anotherKey2":"Martin"
}
}
This is the code:
Data data = new Gson().fromJson(json, Data.class);
Here is the Data class:
public class Data {
public String key1;
public Map key2; //This will break everything.
}
What I expect (I am new to GSON) is that it produces the value of key2 as a Map object.
However, I get an error Expected BEGIN_OBJECT but was STRING which makes me think that I am passing a String, where I should be passing a JSON object.
Isn't GSON parsing the whole JSON string I pass in the beginning? So eventually, I would like the new data source to be a Map Object. Is that feasible ?
Let Gson do the work. I defined Data as
package stackoverflow.questions.q19228349;
public class Data {
#Override
public String toString() {
return "Data [key1=" + key1 + ", key2=" + key2 + "]";
}
public String key1;
public Object key2;
}
and then I can parse both cases for key2:
package stackoverflow.questions.q19228349;
import com.google.gson.Gson;
public class Q19228349 {
public static void main(String[] args){
String json =
"{\"key1\":\"someValue\","+
"\"key2\":{ "+
" \"anotherKey1\":\"212586425\","+
" \"anotherKey2\":\"Martin\""+
" }"+
" }";
String json2 =
"{\"key1\":\"someValue\","+
"\"key2\":\"aString\""+
" }";
Gson g = new Gson();
Data d = g.fromJson(json, Data.class);
System.out.println("First: " +d);
Data d2 = g.fromJson(json2, Data.class);
System.out.println("Second: "+d2);
}
}
This is the result:
First: Data [key1=someValue, key2={anotherKey1=212586425,
anotherKey2=Martin}] Second: Data [key1=someValue, key2=aString]
I'm trying to parse some JSON data using gson in Java that has the following structure but by looking at examples online, I cannot find anything that does the job.
Would anyone be able to assist?
{
"data":{
"id":[
{
"stuff":{
},
"values":[
[
123,
456
],
[
123,
456
],
[
123,
456
],
],
"otherStuff":"blah"
}
]
}
}
You just need to create a Java class structure that represents the data in your JSON. In order to do that, I suggest you to copy your JSON into this online JSON Viewer and you'll see the structure of your JSON much clearer...
Basically you need these classes (pseudo-code):
class Response
Data data
class Data
List<ID> id
class ID
Stuff stuff
List<List<Integer>> values
String otherStuff
Note that attribute names in your classes must match the names of your JSON fields! You may add more attributes and classes according to your actual JSON structure... Also note that you need getters and setters for all your attributes!
Finally, you just need to parse the JSON into your Java class structure with:
Gson gson = new Gson();
Response response = gson.fromJson(yourJsonString, Response.class);
And that's it! Now you can access all your data within the response object using the getters and setters...
For example, in order to access the first value 456, you'll need to do:
int value = response.getData().getId().get(0).getValues().get(0).get(1);
Depending on what you are trying to do. You could just setup a POJO heirarchy that matches your json as seen here (Preferred method). Or, you could provide a custom deserializer. I only dealt with the id data as I assumed it was the tricky implementation in question. Just step through the json using the gson types, and build up the data you are trying to represent. The Data and Id classes are just pojos composed of and reflecting the properties in the original json string.
public class MyDeserializer implements JsonDeserializer<Data>
{
#Override
public Data deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException
{
final Gson gson = new Gson();
final JsonObject obj = je.getAsJsonObject(); //our original full json string
final JsonElement dataElement = obj.get("data");
final JsonElement idElement = dataElement.getAsJsonObject().get("id");
final JsonArray idArray = idElement.getAsJsonArray();
final List<Id> parsedData = new ArrayList<>();
for (Object object : idArray)
{
final JsonObject jsonObject = (JsonObject) object;
//can pass this into constructor of Id or through a setter
final JsonObject stuff = jsonObject.get("stuff").getAsJsonObject();
final JsonArray valuesArray = jsonObject.getAsJsonArray("values");
final Id id = new Id();
for (Object value : valuesArray)
{
final JsonArray nestedArray = (JsonArray)value;
final Integer[] nest = gson.fromJson(nestedArray, Integer[].class);
id.addNestedValues(nest);
}
parsedData.add(id);
}
return new Data(parsedData);
}
}
Test:
#Test
public void testMethod1()
{
final String values = "[[123, 456], [987, 654]]";
final String id = "[ {stuff: { }, values: " + values + ", otherstuff: 'stuff2' }]";
final String jsonString = "{data: {id:" + id + "}}";
System.out.println(jsonString);
final Gson gson = new GsonBuilder().registerTypeAdapter(Data.class, new MyDeserializer()).create();
System.out.println(gson.fromJson(jsonString, Data.class));
}
Result:
Data{ids=[Id {nestedList=[[123, 456], [987, 654]]}]}
POJO:
public class Data
{
private List<Id> ids;
public Data(List<Id> ids)
{
this.ids = ids;
}
#Override
public String toString()
{
return "Data{" + "ids=" + ids + '}';
}
}
public class Id
{
private List<Integer[]> nestedList;
public Id()
{
nestedList = new ArrayList<>();
}
public void addNestedValues(final Integer[] values)
{
nestedList.add(values);
}
#Override
public String toString()
{
final List<String> formattedOutput = new ArrayList();
for (Integer[] integers : nestedList)
{
formattedOutput.add(Arrays.asList(integers).toString());
}
return "Id {" + "nestedList=" + formattedOutput + '}';
}
}
The server I am working with returns an json object which contains a list of objects, not just one.
{
"1":{"id":"1","value":"something"},
"2":{"id":"2","value":"some other thing"}
}
I want to convert this json object into an object array.
I know I can use Gson, and create a class like this:
public class Data {
int id;
String value;
}
and then use
Data data = new Gson().fromJson(response, Data.class);
But it's only for the objects inside the json object.
I don't know how to convert json object with number as keys.
Or alternatively I need to alter the server to response to something like this?:
{["id":"1","value":"something"],["id":"2","value":"some other thing"]}
But I don't want to change to server as I have to change all the client side codes.
Your JSON looks really weird. If you can't change it, you have to deserialize it to Map. Example source code could looks like this:
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
public class GsonProgram {
public static void main(String... args) throws Exception {
Gson gson = new GsonBuilder().create();
String json = "{\"1\":{\"id\":\"1\",\"value\":\"something\"},\"2\":{\"id\":\"2\",\"value\":\"some other thing\"}}";
Type type = new TypeToken<HashMap<String, HashMap<String, String>>>() {}.getType();
Map<String, Map<String, String>> map = gson.fromJson(json, type);
for (Map<String, String> data : map.values()) {
System.out.println(Data.fromMap(data));
}
}
}
class Data {
private int id;
private String value;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public String toString() {
return "Data [id=" + id + ", value=" + value + "]";
}
public static Data fromMap(Map<String, String> properties) {
Data data = new Data();
data.setId(new Integer(properties.get("id")));
data.setValue(properties.get("value"));
return data;
}
}
Above program prints:
Data [id=2, value=some other thing]
Data [id=1, value=something]
Because this json object uses int as the field key that you cannot specify the field key name when deserialize it. Thus I need to extract the value set from the set first:
JsonParser parser = new JsonParser();
JsonObject obj = parser.parse(json).getAsJsonObject();
Set<Entry<String,JsonElement>> set = obj.entrySet();
Now "set" contains a set of , in my case is <1,{id:1,value:something}>.
Because the key is useless here, I only need the value set, so I iterate the set to extract the value set.
for (Entry<String,JsonElement> j : set) {
JsonObject value = (JsonObject) j.getValue();
System.out.println(value.get("id"));
System.out.println(value.get("value"));
}
If you have more complex structure, like nested json objects, you can have something like this:
for (Entry<String,JsonElement> j : locations) {
JsonObject location = (JsonObject) j.getValue();
JsonObject coordinate = (JsonObject) location.get("coordinates");
JsonObject address = (JsonObject) location.get("address");
System.out.println(location.get("location_id"));
System.out.println(location.get("store_name"));
System.out.println(coordinate.get("latitude"));
System.out.println(coordinate.get("longitude"));
System.out.println(address.get("street_number"));
System.out.println(address.get("street_name"));
System.out.println(address.get("suburb"));
}
Hope it helps.