I hava a pojo with lots of classes attached to it. Wanted to know the JSON structure to be passed to the API.
Is there any way to create the json structure (with some fake data)?
Example:
public class Staff {
private String personName;
private Salary salary;
private String[] position; // Array
private List<Department> department; // List
private Map<String, Address> addressMap; // Map
// getters & setters of those too.
}
The Department has more number of POJOs within it (person joining to the department data)
Salary has rivisions of each designations.
so and so.
I am trying to get a JSON struture of this without creating it manually.
Something like this (Expected output)
{
"person_name": "person_name",
"salary": {
"joining_salary": "0",
"designation": {
"joining_designation": "joining_designation",
"some_data": "some_data"......
}
},
"department": {
"current_department": {
"latitude": 59.331132099999998,
"longitude": 18.066796700000001,
"address": {
"address_line": "address_line",
"city_name": "city_name",
"zip_code": "zip_code",
"country_code": "co" ....> Restricted to 2 charactors
}
}
},
"some_other": [
"...."
],
"some": "some"
}
You can use the com.google.code.gson library
Maven dependency is as below
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
You can try the following,
Staff staff = new Staff();
// create your objects as required
Gson gson = new Gson();
// below jsonString will have the JSON structure of staff Object
String jsonString = gson.toJson(staff)
I prefer using special and very powerful tool called “Jackson”
It can convert in both directions POJO -> JSON and JSON -> POJO
It also works with other input formats such as YAML etc
The usage is simple;
// Creates default JSON mapper
ObjectMapper mapper = new ObjectMapper();
// Initialize your root object (it could be not necessarily “Stuff”)
// including all nested classes and fields. Any dummy data is
// applicable for your purposes.
Staff staff = new Staff();
// Write object to JSON in file:
mapper.writeValue(new File("c:\\staff.json"), staff);
Jackson Dependency in Maven Repo
you can use the gson, fastjson or Jackson
https://www.2json.net/article/45
Related
If an "action" key-value pair is repeated, I want to append each associated "myObject" to a list as shown below. Is there a way to achieve this using GSON or JACKSON? Unfortunately, there is no option to edit the input JSON. If the ask is not clear, please let me know.
Input
[
{
myObject: {
name: "foo",
description: "bar"
},
action: "create",
},
{
myObject: {
name: "baz",
description: "qux"
},
action: "create",
},
];
Required Output
{
"action": "create",
"myObject": [
{
name: "foo",
description: "bar"
},
{
name: "baz",
description: "qux"
},
]
};
I am new to JSON parsing in Java and unfortunately haven't found a use case like mine on StackOverflow. I have tried configuring my ObjectMapper like so -
new ObjectMapper().configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
and using
#JsonAnySetter
annotation, but haven't gotten them to work yet.
You could solve this with two separate model classes, one for the original structure and one for the transformed one. For simplicity I call them OriginalModel and TransformedModel below, you should probably pick more meaningful names. The following code uses Gson but you can probably achieve something similar with Jackson as well.
class OriginalModel {
String action;
MyObjectData myObject;
}
class TransformedModel {
String action;
List<MyObjectData> myObject;
public TransformedModel(String action, List<MyObjectData> myObject) {
this.action = action;
this.myObject = myObject;
}
}
class MyObjectData {
String name;
String description;
}
If you declare these classes as nested classes you should make them static.
Then you can first parse the JSON data with the original model class, manually create the desired result structure using the transformed class and serialize that to JSON:
Gson gson = new Gson();
List<OriginalModel> originalData = gson.fromJson(json, new TypeToken<List<OriginalModel>>() {});
// Group MyObjectData objects by action name
// Uses LinkedHashMap to preserve order
Map<String, List<MyObjectData>> actionsMap = new LinkedHashMap<>();
for (OriginalModel model : originalData) {
actionsMap.computeIfAbsent(model.action, k -> new ArrayList<>())
.add(model.myObject);
}
List<TransformedModel> transformedData = new ArrayList<>();
for (Map.Entry<String, List<MyObjectData>> entry : actionsMap.entrySet()) {
transformedData.add(new TransformedModel(entry.getKey(), entry.getValue()));
}
String transformedJson = gson.toJson(transformedData);
I Have a REST api that contains the data like this way
{
...
... //<- more data here
...
"currencies": {
"BTN": {
"name": "Bhutanese ngultrum",
"symbol": "Nu."
},
"INR": {
"name": "Indian rupee",
"symbol": "₹"
}
}
...
... //<- more data here
...
}
i am doing a project in java where i need to use okhttp and show information about a country from an available rest api and before when i used this api it had all the data in currencies in an data array and that was helpful as you can just get the first zero object from the array , but after they updated the api they made all data in currencies an object and i only want the first object , any way i can get it?
OK, so you have two options here ...
Option 1.
Create two classes like this and use ObjectMapper class to do automatic deserealisation for you.
class CurrencyData {
String name;
String symbol;
}
class CurrencyJsonResponse {
CurrencyData INR;
CurrencyData BTN;
}
public static void main(String[] args) {
OkHttpClient client = // build an instance;
ObjectMapper objectMapper = new ObjectMapper();
ResponseBody responseBody = client.newCall(request).execute().body();
CurrencyJsonResponse currencyResponse = objectMapper.readValue(responseBody.string(), CurrencyJsonResponse.class);
//Get data by using getters on currencyResponse object
}
Option 2
You can write a custom deserealizer by extending the StdDeserializer<T> class. You'll have to programmatically inspect the JsonNode parse tree and assemble the object that you want.
This article explains how to do it and comes with a working code sample
I am trying to process the JSON output from https://api.exchangeratesapi.io/latest in my Android app, which is returned in this format:
{
"rates": {
"CAD": 1.5613,
"HKD": 8.9041,
...
"KRW": 1374.71,
"MYR": 4.8304
},
"base": "EUR",
"date": "2020-03-09"
}
I would like to use GSON to process this JSON, so I have added a class ExchangeRates to recieve the data:
class ExchangeRates {
private String base;
private String date;
}
These commands load the JSON into my ExchangeRates class:
Gson gson = new Gson();
ExchangeRates mExchangeRates = gson.fromJson(result, ExchangeRates.class);
However, I cannot figure out how to load the associative array of exchange rates into the class in a scalable manner. I know I could add a static list of the currencies, but I want the code to be able to automatically handle additional currencies if they are added at a later date.
It turned out to be very simple, and yes, #ya379, a HashMap was part of the answer. Given a HashMap data type, GSON will translate the associative array part of the JSON directly to a HashMap:
class ExchangeRates {
private String base;
private String date;
private HashMap<String, Double> rates;
}
I'm using GSON in Android to parse a JSON object, part of which contains multiple nested objects holding all of the same fields. For example, the JSON structure looks similar to this:
{
"name": "nestedJSONExample",
"divisions": {
"division1": {
"id": string
"name": string,
"alsoKnownAs": [
string
],
}
"division2": {
"id": string
"name": string,
"alsoKnownAs": [
string
],
}
...
"division99" {
"id": string
"name": string,
"alsoKnownAs": [
string
],
}
}
}
In this example all of the "division##" nested objects contain all of the same fields, is there a way to parse this JSON into a Java class without creating model classes for each "division##" object?
i.e. can I create a Java structure like:
divisions.division##.id
without having to make classes for each individual division?
You seem to have a little confusion: you don't need a mapping class for each division## node since you can reuse one class multiple times regardless the property names. You might need from zero to two custom mapping classes regarding the way you prefer:
0 custom mapping classes if traversing a parsed JSON object on your own;
1 custom mapping class if applying advanced parsing techniques and combining the mapping with type adapters or JSON objects;
2 custom mapping classes for exact mapping.
The examples below are written with Java 8 language features and Java 8 Stream API but can be re-written with Java 6 easily. The JSON constant below is just a String with the following JSON document:
{
"name": "nestedJSONExample",
"divisions": {
"division1": {"id": "id1", "name": "name1", "alsoKnownAs": ["alsoKnownAs1A"]},
"division2": {"id": "id2", "name": "name2", "alsoKnownAs": ["alsoKnownAs2A"]},
"division3": {"id": "id3", "name": "name3", "alsoKnownAs": ["alsoKnownAs3A"]},
"division4": {"id": "id4", "name": "name4", "alsoKnownAs": ["alsoKnownAs4A"]},
"division5": {"id": "id5", "name": "name5", "alsoKnownAs": ["alsoKnownAs5A"]},
"division6": {"id": "id6", "name": "name6", "alsoKnownAs": ["alsoKnownAs6A"]}
}
}
No mappings
JsonElement is a built-in Gson class representing any JSON element. Combining JsonElement class and its child classes elements, Gson can build a JSON tree that reflects a given JSON document structure. So just traversing from the root is enough.
final Gson gson = new Gson();
final List<String> ids = gson.fromJson(JSON, JsonElement.class)
.getAsJsonObject()
.get("divisions") // get the divisions property
.getAsJsonObject()
.entrySet() // and traverse its key/value pairs
.stream()
.map(Entry::getValue) // discarding the keys
.map(JsonElement::getAsJsonObject)
.map(jo -> jo.get("id")) // take the id property from the every `division` object
.map(JsonElement::getAsJsonPrimitive)
.map(JsonPrimitive::getAsString)
.collect(toList());
System.out.println(ids);
Exact mappings
Here you could need just two mapping classes to describe the relations between JSON objects. The divisions node can be just a Map holding arbitrary keys and Division values.
final class OuterWithMap {
//String name;
Map<String, Division> divisions;
}
final class Division {
String id;
//String name;
//List<String> alsoKnownAs;
}
final Gson gson = new Gson();
final List<String> ids = gson.fromJson(JSON, OuterWithMap.class)
.divisions
.values() // use map values only ignoring the keys
.stream()
.map(d -> d.id)
.collect(toList());
System.out.println(ids);
Not exact mappings
This is the most complicated one and shows advanced techniques in parsing JSON with Gson and mapping given JSON documents to mapping classes may not reflect the real structure therefore making transformations on-fly.
final class OuterWithList {
//String name;
#JsonAdapter(NoKeysTypeAdapterFactory.class)
List<Division> divisions;
}
final class NoKeysTypeAdapterFactory
implements TypeAdapterFactory {
// No accessible constructor needed - Gson can instantiate it itself
private NoKeysTypeAdapterFactory() {
}
#Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
// Is it a list?
if ( List.class.isAssignableFrom(typeToken.getRawType()) ) {
// Try to determine the list element type
final Type elementType = getElementType(typeToken.getType());
// And create a custom type adapter instance bound to the specific list type
#SuppressWarnings("unchecked")
final TypeAdapter<T> typeAdapter = (TypeAdapter<T>) getNoKeysTypeAdapter(gson, elementType);
return typeAdapter;
}
// Otherwise just tell Gson try to find another appropriate parser
return null;
}
private static Type getElementType(final Type type) {
// Is it a generic type with type parameters?
if ( type instanceof ParameterizedType ) {
final ParameterizedType parameterizedType = (ParameterizedType) type;
// If yes, then just take the first type argument since java.util.List can only one type
return parameterizedType.getActualTypeArguments()[0];
}
// Otherwise java.lang.Object due to either Java generics type erasure or raw types usage
return Object.class;
}
}
final class NoKeysTypeAdapter<E>
extends TypeAdapter<List<E>> {
private final Gson gson;
private final Type elementType;
private NoKeysTypeAdapter(final Gson gson, final Type elementType) {
this.gson = gson;
this.elementType = elementType;
}
static <E> TypeAdapter<List<E>> getNoKeysTypeAdapter(final Gson gson, final Type elementType) {
return new NoKeysTypeAdapter<>(gson, elementType);
}
#Override
public void write(final JsonWriter out, final List<E> value) {
throw new UnsupportedOperationException();
}
#Override
public List<E> read(final JsonReader in)
throws IOException {
final List<E> list = new ArrayList<>();
// Make sure that the next JSON stream token is `{`
in.beginObject();
// Read until the object ends
while ( in.peek() != END_OBJECT ) {
// Ignore the found JSON object property name
in.nextName();
// And delegate the property value parsing to a downstream parser
final E element = gson.fromJson(in, elementType);
list.add(element);
}
// Make sure that the JSON stream is finished with the `}` token
in.endObject();
return list;
}
}
Using a special querying library
There are some libraries like JsonPath that can make querying JSON documents somewhat easier. JsonPath can work without Gson, however, as far as I understand, it uses another JSON parsing library, and does not parse JSON itself (but I don't know how it actually is). Example of use:
final JsonPath jsonPath = JsonPath.compile("$.divisions.*.id");
final List<String> ids = jsonPath.<JSONArray>read(JSON)
.stream()
.map(o -> (String) o)
.collect(toList());
System.out.println(ids);
All four examples above have the following output:
[id1, id2, id3, id4, id5, id6]
Using GSON your best bet is to write a custom Deserializer (example) or a TypeAdapter (example), this will allow you to do whatever you want with the structure then return a single (top level) object
I am trying to map the following response:
{
"data": {
"id": "1574083",
"username": "snoopdogg",
"full_name": "Snoop Dogg",
"profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_1574083_75sq_1295469061.jpg",
"bio": "This is my bio",
"website": "http://snoopdogg.com",
"counts": {
"media": 1320,
"follows": 420,
"followed_by": 3410
}
}
into an object where I only want to retrieve the username, full_name, and id fields.
Ex: something like:
public class User{
String id;
String username;
String full_name;
// getters + setters
}
Is there a way of doing this without first having to store the data object into a Map?
Use Jackson API. It should be simple:
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(jsonString, User.class); //jsonString is your actual json string.
You might want to tweak your User class to match the JSON string. E.g. your user class needs to have a 'data' field as List<Data> data; where 'Data' is another POJO. You can add the "id", "userName", etc fields in the 'Data' pojo.
You can either do it by hand via, for example, regexp or utilize any of JSON libraries like Jackson, GSON etc.
With GSON it's pretty simple. Say your json is stored in a String jsonString variable.
Gson gson = new Gson();
YourObject = gson.fromJson(jsonString, YourObject.class);
Although I'm not sure what will happen, since your jsonString doesn't have a key called User. However, this should work if you first extract data from your jsonString and name your POJO Data.