Create an empty list of arrays in Jackson - java

I'm using Jackson to serialize and deserialize JSON objects to and from POJO-s.
One of the elements I'm trying to create is a list of arrays (I think that's what this would be called).
"Images": [
{}
],
I've tried:
public ArrayList<String> Images = new ArrayList<String>();
and then just didn't add anything to it then called the object mapper.
That unfortunately gave me just a list:
"Images":[
]
I then tried to make it an list of string arrays:
public ArrayList<String[]> Images = new ArrayList<String[]>();
I added an empty array to my ArrayList:
String[] tempArray = {};
Images.add(tempArray);
But that gave me:
"Images":[
[]
],
How can I get the needed format?

What you describing is a list of objects, which would be:
public ArrayList<yourObject> Images = new ArrayList<yourObject>();
This would give you the:
"Images": [
{}
]
If you want a list of arrays, you would do:
public ArrayList<ArrayList<yourObject> Images = new ArrayList<ArrayList<yourObject>();
this would give you:
"Images":[
[]
]

JSON not-primitives in Java can be represented by:
JSON Array - [] => java.util.List or array.
JSON Object - {} => java.util.Map or POJO class.
If you need empty JSON Object you can use empty map or empty POJO - POJO without properties or with all properties set to null and with ObjectMapper set to ignore null-s.
Simple example which generates desired output could look like below:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class JsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(new Root());
System.out.println(json);
}
}
class Root {
private static final List<Map<String, Object>> EMPTY_MAP_IN_ARRAY = Collections.singletonList(Collections.emptyMap());
#JsonProperty("Images")
private List<Map<String, Object>> images = EMPTY_MAP_IN_ARRAY;
public List<Map<String, Object>> getImages() {
return images;
}
public void setImages(List<Map<String, Object>> images) {
this.images = images;
}
}
Above code prints:
{"Images":[{}]}

Related

Gson: Get an array of objects which is nested in an object, which in turn is nested in an entire JSON object

Edit
I'd love to hear any solution. It doesn't have to be with Gson. Also, if you know a good tutorial about parsing nested JSON, I'd love if you would tell me its name or provide a link.
How many SQLite table are required? as of now I have one table. Does every nested object requires a table?
The original question
I'm trying to get this nested array of objects with Gson. I tried using TypeToken but I couldn't find the rules on how to inplement TypeToken (such rules might have helped in using TypeToken for a specific JSON).
The JSON
{
"_embedded": {
"episodes":[
{
"name": "Probe",
"summary": "adasdasdas"
},
{...},
{...}
]
}
}
What I tried:
// inserting the JSON to SQLite
private void insertToSQLite(SQLiteDatabase db) {
Gson gson = new Gson();
Type listType = new TypeToken<List<Episode>>(){}.getType();
List<Episode> episodesList = gson.fromJson(output, listType);
for(Episode episode : episodesList) {
ContentValues insertValues = new ContentValues();
insertValues.put(Episode.ID, episode.getId());
insertValues.put(Episode.TITLE, episode.getTitle());
insertValues.put(Episode.SUMMARY, episode.getSummary());
...
}
}
Thanks.
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
public class TestJson {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Gson gson = new Gson();
String jsonString = "{\"_embedded\": { \"episodes\":[{\"name\": \"Probe\",\"summary\": \"adasdasdas\" }]}}";
JsonElement jsonObject = new JsonParser().parse(jsonString).getAsJsonObject().get("_embedded").getAsJsonObject()
.get("episodes");
Type listType = setModelAndGetCorrespondingList(Episode.class);
List<Episode> episodes = gson.fromJson(jsonObject, listType);
System.out.println(episodes);
}
private static <T> Type setModelAndGetCorrespondingList(Class<T> type) {
return new TypeToken<ArrayList<T>>() {
}.where(new TypeParameter<T>() {
}, type).getType();
}
}

How to parse a Java List of already parsed JSON into a Big JSON?

I use Jackson to serialize/deserialize JSON.
I have a List<String> in which all elements inside are already serialized in JSON format. I would like to generate a big JSON from that List.
In other word, I have:
List<String> a = new ArrayList<>();
a[0] = JSON_0
a[1] = JSON_1
...
a[N] = JSON_N
And I would like to render:
[
{JSON_0},
{JSON_1},
...
{JSON_N}
]
What is the best way to do so using Jackson?
Probably the simpler solution would be to create ArrayNode and use addRawValue method:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.util.RawValue;
public class JsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ArrayNode nodes = mapper.getNodeFactory().arrayNode();
nodes.addRawValue(new RawValue("{}"));
nodes.addRawValue(new RawValue("true"));
nodes.addRawValue(new RawValue("{\"id\":1}"));
System.out.println(mapper.writeValueAsString(nodes));
}
}
Above code prints:
[{},true,{"id":1}]
You can also, create a POJO with list and use #JsonRawValue annotation. But if you can not have extra root object you need to implement custom serialiser for it. Example with POJO and custom serialiser:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class JsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
List<String> jsons = new ArrayList<>();
jsons.add("{}");
jsons.add("true");
jsons.add("{\"id\":1}");
RawJsons root = new RawJsons();
root.setJsons(jsons);
System.out.println(mapper.writeValueAsString(root));
}
}
#JsonSerialize(using = RawJsonSerializer.class)
class RawJsons {
private List<String> jsons;
public List<String> getJsons() {
return jsons;
}
public void setJsons(List<String> jsons) {
this.jsons = jsons;
}
}
class RawJsonSerializer extends JsonSerializer<RawJsons> {
#Override
public void serialize(RawJsons value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartArray();
if (value != null && value.getJsons() != null) {
for (String json : value.getJsons()) {
gen.writeRawValue(json);
}
}
gen.writeEndArray();
}
}
If you need to have SerializationFeature.INDENT_OUTPUT feature enabled for all items in array, you need to deserialise all inner objects and serialise them again.
See also:
How can I include raw JSON in an object using Jackson?
Handling raw JSON values using Jackson
the simple fact of having the character '[' we are marking that it is an array so what I recommend to put the list into a JSON array.
I would need a little more information to help you, since it doesn't make much sense to use a JSON String, since a JSON is composed of Key / Value, it is best to make a bean / object with the attribute.
Example:
class Object {
private String attribute = value;
}
{attribute: value}

Jackson -- parse json using xpath or similar

I have some json and it's fairly complex -- (a bit too complex and open-ended to model using something like gson), and I need to extract string values from certain nodes into a list of strings.
The following code works, but due to the way my json works -- it's grabbing lots of extra stuff that I don't want (note: I don't own the json schema)
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(json);
List<JsonNode> keys = node.findValues("key") ;
for(JsonNode key: keys){
System.out.println(key.toString());
}
The contents of Json is fairly complex (Jira filter export) which looks like this:
{
"issues": [
{
"key":"MIN-123",
...
"fields":{
"key":"A_Elric"
}
}
]
}
Assertions:
I always want to extract issues[x].key and not any of the subkeys. I would prefer to extract this into a list, but any normal data structure is fine. I'm already using Jackson -- but gson is also an option if there's a sane way of doing so.
Thanks for the assist!
JsonPath is xpath for json, and it has a Java implementation.
Here is a working example to get issue keys without subkeys:
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
public class JsonPathTest {
public static String ROOT_ARRAY = "issues";
public static String KEY = "key";
// get all KEYs right under ROOT array
public static String jsonPath = String.format("$.%s[*].%s", ROOT_ARRAY, KEY);
public static void main(String[] args) {
try {
String jsonStr = new String(Files.readAllBytes(Paths.get("c:/temp/xx.json")));
Object jsonObj = Configuration.defaultConfiguration().jsonProvider().parse(jsonStr);
List<String> keys = JsonPath.parse(jsonObj).read(jsonPath);
System.out.println(keys);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ExportFilter{
private static final String KEY = "key";
private List<Map<String,Object>> issues = new ArrayList<>();
//getters and setters
#JsonIgnore
public List<String> getKeys(){
return issues.stream()
.map(issue-> issue.get(KEY))
.filter(Objects::nonNull)
.map(Objects::toString)
.collect(toList());
}
}
Example usage:
ObjectMapper objectMapper = new ObjectMapper();
List<String> keys = objectMapper.readValue( .., ExportFilter.class).getKeys();

Converting json object to tsv format in java

I have the following class
public class Params {
private String dataType;
private Map<String, List<String>> group;
private List<Aggregate> aggregates;
private List<String> scene;
private List<String> company;
private List<Map<String, List<String>>> fit;
private Map<String, String> params;
private String tempo;
private String id;
private String valuation;
}
In order to convert it to a tsv, I have serialized it to json using:
public String put(final Params parameter) {
serializedParams = JsonSerializer.serialize(params);
}
So I get something like this as an output:
{
"dataType" : "abc",
"group" : { },
"aggregates" : [ ],
"scene" : [ "AC" ],
"company" : [ "pr" ],
"fit" : [ {
"prod" : [ "A1" ]
} ],
"params" : null,
"tempo" : "note",
"id" : "123",
"valuation" : USD
}
My eventual output is getting something like this (tab-separated):
abc AC pr prod A1 note 123 USD
I tried using :
parameter.getGroup.values()
This, however, only gives the values present in a format like [ val ].
How can I get all the values of the object simultaneously? Is it possible to get values from a map, list etc simultaneously without separate processing?
Any help would be appreciated.
It's not quite clear from your question exactly how you want to handle your data when generating your tabbed output for certain scenarios, but I'll try to provide some sample code to help you.
First, however, I want to say that it's not a good idea to serialize to JSON and then serialize JSON to tab separated values. You're doing 2 steps when you could be doing one, the JSON serialization doesn't get you any closer to your goal, and serialization is generally a costly process - you don't want to do it more than you have to.
So with that in mind here's a quick example of how you might implement a simple tab delimited serialization:
Since you have at least one custom object to deal with inside of your Params class (referring to the List of Aggregateobjects) I would suggest creating an interface that your classes can implement to indicate they are able to be serialized into a tab delimited string.
I simply called this interface TabSerializable:
public interface TabSerializable {
public String toTabbedString();
}
Next, I modified your Params class to implement this interface:
public class Params implements TabSerializable{
//fields omitted for brevity.
...
public String toTabbedString(){
StringJoiner joiner = new StringJoiner("\t");
TabSerializer.addValue(dataType, joiner);
TabSerializer.addValue(group, joiner);
TabSerializer.addValue(aggregates, joiner);
TabSerializer.addValue(scene, joiner);
TabSerializer.addValue(company, joiner);
TabSerializer.addValue(fit, joiner);
TabSerializer.addValue(params, joiner);
TabSerializer.addValue(tempo, joiner);
TabSerializer.addValue(id, joiner);
TabSerializer.addValue(valuation, joiner);
return joiner.toString();
}
...
}
I also created a sample Aggregate class which also implements this interface:
public class Aggregate implements TabSerializable{
private String data;
#Override
public String toTabbedString() {
return data;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
Since you have mostly generic types of data structures like maps and lists I created the TabSerializer class to help transform those structures into tab delimited strings:
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
public class TabSerializer {
private static void addValuesFromMap(Map<?,?> obj, StringJoiner joiner) {
for(Object key: obj.keySet()){
Object value = obj.get(key);
if(value == null){
continue;
}
addValue(key, joiner);
addValue(value, joiner);
}
}
private static void addValuesFromList(List<?> arr, StringJoiner joiner) {
for(int i=0; i<arr.size(); i++){
Object value = arr.get(i);
addValue(value, joiner);
}
}
public static void addValue(Object value, StringJoiner joiner){
if(value == null){
return;
}
if(value instanceof List){
addValuesFromList((List<?>)value, joiner);
}else if(value instanceof Map){
addValuesFromMap((Map<?,?>)value, joiner);
}else if(value instanceof TabSerializable){
joiner.add(((TabSerializable) value).toTabbedString());
}else{
joiner.add(String.valueOf(value));
}
}
}
Based on the example you gave in your question I wrote the logic above to skip null values and the names of fields at the top level (those fields in the Params class).
Finally I created a class with a main to test the above logic:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MainTabDelim {
public static void main(String[] args) {
Params params = new Params();
params.setDataType("abc");
List<String> scene = new ArrayList<>();
scene.add("AC");
params.setScene(scene);
List<String> company = new ArrayList<>();
company.add("pr");
params.setCompany(company);
List<Map<String, List<String>>> fit = new ArrayList<>();
List<String> fitInner = new ArrayList<>();
fitInner.add("A1");
Map<String, List<String>> fitMap = new HashMap<>();
fitMap.put("prod", fitInner);
fit.add(fitMap);
params.setFit(fit);
params.setTempo("note");
params.setId("123");
params.setValuation("USD");
// Uncomment the following lines to see how Aggregate works:
// List<Aggregate> aggregates = new ArrayList<>();
// Aggregate ag = new Aggregate();
// ag.setData("some_data");
// aggregates.add(ag);
// params.setAggregates(aggregates);
System.out.println(params.toTabbedString());
}
}
The output is:
abc AC pr prod A1 note 123 USD
I hope this helps you to get started. Enjoy!
Same CSV generate code you have to use, and only add a few things when you create the TSV file as below
try (CSVWriter writer = new CSVWriter(new FileWriter("src/main/resources/test2.tsv"),
'\t',
CSVWriter.NO_QUOTE_CHARACTER,
CSVWriter.DEFAULT_ESCAPE_CHARACTER,
CSVWriter.DEFAULT_LINE_END)) {
writer.writeAll(dataLines);
}
I used OpenCsV maven library

Resteasy: how to save JSON with not fixed keys

I use reasteasy to call REST API.
My problem is that the JSON from the REST API has dynamic values. For example:
"labels": {
"kubernetes.io/hostname": "192.168.200.176",
"node": "master"
}
Where "node" and "kubernetes.io/hostname" could be any string.
I've tried to map "labels" into a Map <String, String> object. The variable is correctly created but it remains empty. How can I generate a dictionary with for example {"kubernetes.io/hostname": "192.168.200.176", "node": "master"}?`
If you're fine with just creating a Map instead of a specific domain object, you can simply parse the JSON yourself to get a list of the keys and create the Map yourself.
Here's an example using org.json:
import java.util.HashMap;
import java.util.Map;
import org.json.JSONObject;
public class Scratch {
public static void main(String[] args) throws Exception {
String json = "{ \"labels\": { \"kubernetes.io/hostname\": \"192.168.200.176\", \"node\": \"master\" } }";
Map<String, String> library = new HashMap<>();
// parse the input string
JSONObject labels = new JSONObject(json).getJSONObject("labels");
// iterate over keys and insert into Map
for (String key : labels.keySet()) {
library.put(key, labels.getString(key));
}
System.out.println(library);
// {kubernetes.io/hostname=192.168.200.176, node=master}
}
}
You can also do more-or-less the same thing with Gson, by simply wrapping the Map in a container class, and letting it do the actual deserialization:
import java.util.Map;
import com.google.gson.Gson;
public class Scratch {
public static void main(String[] args) throws Exception {
String json = "{ \"labels\": { \"kubernetes.io/hostname\": \"192.168.200.176\", \"node\": \"master\" } }";
Library library = new Gson().fromJson(json, Library.class);
System.out.println(library.labels);
// {kubernetes.io/hostname=192.168.200.176, node=master}
}
}
class Library {
Map<String, String> labels;
}
In both cases, notice that you have to get the data from inside the "labels" field of the JSON, not the top level.

Categories

Resources