I have some code that takes in a list of descriptors and writes them to different JSON files using the GSON library. I am now trying to change that library to Jackson. I am not a Jackson expert so I'm looking for some help. Here is my code when I am using GSON:
Descriptor Class:
public class Descriptor {
#SerializedName("BatchName")
private String batchName;
#SerializedName("Metadata")
private Metadata metadata;
#SerializedName("SampleInfo")
private SampleInfoJsonModel sampleInfo;
#SerializedName("Files")
private List<String> files;
#SerializedName("ClientData")
private ClientData clientData;
#SerializedName("CaseName")
private String caseName;
public Descriptor() {
this.metadata = new Metadata();
this.sampleInfo = new SampleInfoJsonModel();
this.files = new ArrayList<String>();
this.clientData = new ClientData();
}
public String getBatchName() {
return batchName;
}
public void setBatchName(String batchName) {
this.batchName = batchName;
}
public Metadata getMetadata() {
return metadata;
}
public void setMetadata(Metadata metadata) {
this.metadata = metadata;
}
public SampleInfoJsonModel getSampleInfo() {
return sampleInfo;
}
public void setSampleInfo(SampleInfoJsonModel sampleInfo) {
this.sampleInfo = sampleInfo;
}
public List<String> getFiles() {
return files;
}
public void setFiles(List<String> files) {
this.files = files;
}
public ClientData getClientData() {
return clientData;
}
public void setClientData(ClientData clientData) {
this.clientData = clientData;
}
public String getCaseName() {
return caseName;
}
public void setCaseName(String caseName) {
this.caseName = caseName;
}
public ClientData getClientDataNoCountryCodes() {
// TODO Auto-generated method stub
return null ;
}
}
My write JSON File function:
public static void writeJsonFile(List<Descriptor> descriptors) {
try {
for(Descriptor descriptor : descriptors) {
BufferedWriter buffWrite = new BufferedWriter(new FileWriter("descriptor_"+descriptor.getCaseName()+".json"));
Gson gson = new GsonBuilder().setPrettyPrinting().create();
buffWrite.write(gson.toJson(descriptor));
buffWrite.close();
}
}
catch (IOException ioe) {
System.err.println("Error while writing to json file in writeJsonFile: ");
ioe.printStackTrace();
}
}
Here is what I have written in Jackson:
BufferedWriter buffWrite = new BufferedWriter(new FileWriter("descriptor_"+descriptor.getCaseName()+".json"));
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
buffWrite.write(mapper.writeValueAsString(descriptor));
Is this the equivalent of the code below in GSON?
BufferedWriter buffWrite = new BufferedWriter(new FileWriter("descriptor_"+descriptor.getCaseName()+".json"));
Gson gson = new GsonBuilder().setPrettyPrinting().create();
buffWrite.write(gson.toJson(descriptor));
buffWrite.close();
I think you are looking for generating a pretty JSON output for your Object and trying to write it into a file.
You have to make sure that you are using #SerializedName equivalent annotation from jackson which is #JsonProperty on your object properties.
Also you can use following to prettify JSON using jackson ObjectMapper
mapper.writerWithDefaultPrettyPrinter().writeValueAsString( descriptorObj )
NOTE that setting SerializationFeature.INDENT_OUTPUT will also help doing the same as you are already thinking.
Also Files APIs are really useful for file related operations.
I hope this will help!
Related
I am coding a Discord Giveaway Bot with Java. I am saving all the details of the Giveaway to a JSON file. Now I want to read the entries list and if the Users ID is not in the list I want to add it and save the file.
Here is the Giveaway Class:
public class Giveaway {
private String prize;
private long time;
private Integer winners;
private List<String> entries;
public Giveaway(String prize, Integer winners, long time, List<String> entries) {
this.prize = prize;
this.winners = winners;
this.time = time;
this.entries = entries;
}
public Giveaway() {}
public String getPrize() {
return prize;
}
public void setPrize(String prize) {
this.prize = prize;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public Integer getWinners() {
return winners;
}
public void setWinners(Integer winners) {
this.winners = winners;
}
public List<String> getEntries() {
return entries;
}
public void setEntries(List<String> entries) {
this.entries = entries;
}
}
When the GW is created the JSON looks like this:
{
"prize": "Discord Nitro",
"time": 1641732935,
"winners": 2,
"entries": []
}
Then when the user clicks a button it should read the list look if the ID is in the list and if not add the id. But when I save the list the whole JSON file changes.
How I read it out and save it:
public class ButtonClick extends ListenerAdapter {
private static Reader reader;
private static Giveaway giveaway = new Giveaway();
public void onButtonClick(ButtonClickEvent event) {
event.deferEdit().queue();
try {
reader = Files.newBufferedReader(Path.of(GiveawayStats.getGiveawayStats().getAbsolutePath()));
} catch (IOException e) {
e.printStackTrace();
}
if (event.getButton().getId().equals("gwEnter")) {
JsonParser parser = new JsonParser();
JsonObject obj = parser.parse(reader).getAsJsonObject();
JsonArray jsonEntries = obj.get("entries").getAsJsonArray();
long time = obj.get("time").getAsLong();
List<String> entries = new ArrayList<>();
for (JsonElement entrie : jsonEntries) {
entries.add(entrie.toString());
}
if (entries.contains(event.getMember().getId())) {
event.getChannel().sendMessage("Already in!").queue();
} else {
entries.add(event.getUser().getId().strip());
printToJson(entries);
}
}
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void printToJson(List<String> entries) {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setVersion(2.0);
Gson gson = gsonBuilder.setPrettyPrinting().create();
giveaway.setEntries(entries);
try (Writer writer = new FileWriter(GiveawayStats.getGiveawayStats().getPath())) {
gson.toJson(giveaway, writer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
After the print so JSON the file looks like this:
{
"time": 0,
"entries": [
"695629580014321747"
]
}
And when I click the Button again it looks like this:
{
"time": 0,
"entries": [
"\"695629580014321747\"",
"695629580014321747"
]
}
So why is my IF condition not working?
You are using entrie.toString() which gives you the string that is used for console output. You should be using entrie.getAsString() instead.
Furthermore, you are also using a lot of deprecated things with JsonParser which should be replaced. new JsonParser().parse(...) should be replaced by JsonParser.parseReader(...).
Above all that, it is highly recommended using a database for this kind of task. Something such as SQLite or Redis would be much better at handling concurrent changes and redundancy. Or at least, you should use a try-with-resources for your reader.
try (Reader reader = ...) {
JsonElement json = JsonParser.parseReader(reader).getAsJsonObject();
...
}
I'm trying to check if config1 exists in a text file, I'm using Google's Gson library.
My JSON file :
{
"maps":{
"config2":{
"component1":"url1",
"component2":"url1",
"component3":"url1"
},
"config1":{
"component1":"url1",
"component2":"url1",
"component3":"url1"
}
}
}
Loading :
public void load() throws IOException {
File file = getContext().getFileStreamPath("jsonfile.txt");
FileInputStream fis = getContext().openFileInput("jsonfile.txt");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader bufferedReader = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
String json = sb.toString();
Gson gson = new Gson();
Data data = gson.fromJson(json, Data.class);
componentURL= data.getMap().get("config1").get("component1");
Saving :
Gson gson = new Gson();
webViewActivity.Data data = gson.fromJson(json, webViewActivity.Data.class);
Map<String, String> configTest = data.getMap().get("config1");
data.getMap().get("config1").put(component, itemUrl);
String json = gson.toJson(data);
String filename = "jsonfile.txt";
FileOutputStream outputStream;
try {
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(json.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
Data class :
public class Data {
private Map<String, Map<String, String>> map;
public Data() {
}
public Data(Map<String, Map<String, String>> map) {
this.map = map;
}
public Map<String, Map<String, String>> getMap() {
return map;
}
public void setMap(Map<String, Map<String, String>> map) {
this.map = map;
}
}
My problem is that I need to create the file once and then check if the file exists, if it does I need to check if config1 exists if it doesn't I need to put config1 in the file.
But I can't check if config1 exists because I get :
java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.Map com.a.app.ui.app.appFragment$Data.getMap()
I check if it exists by doing :
Boolean configTest = data.getMap().containsKey("config1");
if(!configTest){}
How can I create the file and check the data without getting a NullPointerException ?
I think you should modify the way you're handling things.
First create POJO for Config1 each values as:
// file Config1.java
public class Config1
{
private String component1;
private String component2;
private String component3;
public String getComponent1 ()
{
return component1;
}
public void setComponent1 (String component1)
{
this.component1 = component1;
}
public String getComponent2 ()
{
return component2;
}
public void setComponent2 (String component2)
{
this.component2 = component2;
}
public String getComponent3 ()
{
return component3;
}
public void setComponent3 (String component3)
{
this.component3 = component3;
}
#Override
public String toString()
{
return "ClassPojo [component1 = "+component1+", component2 = "+component2+", component3 = "+component3+"]";
}
}
And then after that POJO for Config2
// file Config2.java
public class Config2
{
private String component1;
private String component2;
private String component3;
public String getComponent1 ()
{
return component1;
}
public void setComponent1 (String component1)
{
this.component1 = component1;
}
public String getComponent2 ()
{
return component2;
}
public void setComponent2 (String component2)
{
this.component2 = component2;
}
public String getComponent3 ()
{
return component3;
}
public void setComponent3 (String component3)
{
this.component3 = component3;
}
#Override
public String toString()
{
return "ClassPojo [component1 = "+component1+", component2 = "+component2+", component3 = "+component3+"]";
}
}
And then you need POJO for Maps
// file Maps.java
public class Maps
{
private Config2 config2;
private Config1 config1;
public Config2 getConfig2 ()
{
return config2;
}
public void setConfig2 (Config2 config2)
{
this.config2 = config2;
}
public Config1 getConfig1 ()
{
return config1;
}
public void setConfig1 (Config1 config1)
{
this.config1 = config1;
}
#Override
public String toString()
{
return "ClassPojo [config2 = "+config2+", config1 = "+config1+"]";
}
}
And finally the class which will wrap everything up MyJsonPojo. Though you can rename it to whatever you want.
// file MyJsonPojo.java
public class MyJsonPojo
{
private Maps maps;
public Maps getMaps ()
{
return maps;
}
public void setMaps (Maps maps)
{
this.maps = maps;
}
#Override
public String toString()
{
return "ClassPojo [maps = "+maps+"]";
}
}
Finally replace your code in the loadData() method as:
public void load() throws IOException {
File file = getContext().getFileStreamPath("jsonfile.txt");
FileInputStream fis = getContext().openFileInput("jsonfile.txt");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader bufferedReader = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
String json = sb.toString();
Gson gson = new Gson();
Data data = gson.fromJson(json, MyJsonPojo.class);
Maps maps = data.getMaps();
Config1 config1 = null;
if (maps != null) {
config1 = maps.getConfig1()
}
if (config1 != null) {
componentURL = config1.getComponent1();
}
}
For saving the values you can do this:
public void save() {
// set url here
Component1 component1 = new Component1();
component1.setComponent1(itemUrl);
// store it in maps
Maps maps = new Maps();
maps.setComponent1(component1);
// finally add it to the MyJsonPojo instance
MyJsonPojo myJsonPojo = new MyJsonPojo();
myJsonPojo.setMaps(maps);
Gson gson = new Gson();
String json = gson.toJson(maps);
String filename = "jsonfile.txt";
FileOutputStream outputStream;
try {
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(json.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Please note that you may have to modify the save() code as per your structure because I am quite unsure about how you have handled what in the code. I have provided the basic implementation without much proof reading my code.
I have the following JSON file :
{
"btnsAssign": [
{
"btnCode": 1,
"btnItemTXT": "Baguette",
"btnItemCode": 1001,
"btnAvatarPath": "path"
},
{
"btnCode": 2,
"btnItemTXT": "Petit Pain",
"btnItemCode": 1002,
"btnAvatarPath": "path"
}
]
}
I have the below class :
BtnMenuAssignModel.java
public class BtnMenuAssignModel {
#SerializedName("btnsAssign")
#Expose
private List<BtnsAssign> btnsAssign = null;
public List<BtnsAssign> getBtnsAssign() {
return btnsAssign;
}
public void setBtnsAssign(List<BtnsAssign> btnsAssign) {
this.btnsAssign = btnsAssign;
}
}
BtnsAssign.java
public class BtnsAssign {
#SerializedName("btnCode")
#Expose
private Integer btnCode;
#SerializedName("btnItemTXT")
#Expose
private String btnItemTXT;
#SerializedName("btnItemCode")
#Expose
private Integer btnItemCode;
#SerializedName("btnAvatarPath")
#Expose
private String btnAvatarPath;
public Integer getBtnCode() {
return btnCode;
}
public void setBtnCode(Integer btnCode) {
this.btnCode = btnCode;
}
public String getBtnItemTXT() {
return btnItemTXT;
}
public void setBtnItemTXT(String btnItemTXT) {
this.btnItemTXT = btnItemTXT;
}
public Integer getBtnItemCode() {
return btnItemCode;
}
public void setBtnItemCode(Integer btnItemCode) {
this.btnItemCode = btnItemCode;
}
public String getBtnAvatarPath() {
return btnAvatarPath;
}
public void setBtnAvatarPath(String btnAvatarPath) {
this.btnAvatarPath = btnAvatarPath;
}
}
I need to update some object E.G: object btnItemTXT index 1 from "Petit Pain" to "Pain Complet", How can I?
First convert JSON file to BtnMenuAssignModel then modify BtnMenuAssignModel and convert BtnMenuAssignModel to JSON file:
Gson gson = new Gson();
// read initial json from jsonfile.json
FileReader reader = new FileReader(new File("D:\\codes\\gitlab\\jsonfile.json"));
BtnMenuAssignModel newModel = gson.fromJson(reader, BtnMenuAssignModel.class);
// modify the json object
newModel.getBtnsAssign().forEach(btnsAssign -> {
if (btnsAssign.getBtnCode() == 2) {
btnsAssign.setBtnItemTXT("Pain Complet");
}
});
// write new json string into jsonfile1.json file
File jsonFile = new File("D:\\codes\\gitlab\\jsonfile1.json");
OutputStream outputStream = new FileOutputStream(jsonFile);
outputStream.write(gson.toJson(newModel).getBytes());
outputStream.flush();
This is the right code working for me :
String file = "c:/Users/QAXX2121/Documents/a.json";
try {
Gson gson = new Gson();
// read initial json from jsonfile.json
FileReader reader = new FileReader(new File(file));
BtnMenuAssignModel newModel = gson.fromJson(reader, BtnMenuAssignModel.class);
// modify the json object
newModel.getBtnsAssign().forEach(btnsAssign -> {
if (btnsAssign.getBtnCode() == 2) {
btnsAssign.setBtnItemTXT("Taher");
}
});
// write new json string into jsonfile1.json file
File jsonFile = new File(file);
OutputStream outputStream = new FileOutputStream(jsonFile);
outputStream.write(gson.toJson(newModel).getBytes());
outputStream.flush();
Here's my method where im reading json file.
private void LoadTabaksFromJson() {
InputStream raw = mContext.getResources().openRawResource(R.raw.tabaks);
Reader reader = new BufferedReader(new InputStreamReader(raw));
ListOfTabaks listOfTodos = new Gson().fromJson(reader, ListOfTabaks.class);
List<Tabak> todoList = listOfTodos.getTodoArrayList();
for (Tabak item: todoList){
mDataBase.insert(TabakTable.NAME,null,getContentValues(item));
}
}
public class ListOfTabaks {
protected ArrayList<Tabak> tabakArrayList;
public ArrayList<Tabak> getTodoArrayList(){
return tabakArrayList;
}
}
And Exeption
Caused by: java.lang.NullPointerException: Attempt to invoke interface
method 'java.util.Iterator java.util.List.iterator()' on a null object
reference
at
com.hookah.roma.hookahmix.TabakLab.LoadTabaksFromJson(TabakLab.java:61)
at com.hookah.roma.hookahmix.TabakLab.(TabakLab.java:32)
at com.hookah.roma.hookahmix.TabakLab.get(TabakLab.java:37)
at
com.hookah.roma.hookahmix.TabakListFragment.updateUI(TabakListFragment.java:38)
at
com.hookah.roma.hookahmix.TabakListFragment.onCreateView(TabakListFragment.java:32)
at
android.support.v4.app.Fragment.performCreateView(Fragment.java:2184)
at
android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1298)
at
android.support.v4.app.FragmentManagerImpl.moveFragmentsToInvisible(FragmentManager.java:2323)
at
android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2136)
And json file :
{
"tabaksArrayList":[
{
"name":"Абрикос",
"description":"Со вкусом Абрикоса",
"rating":"4.1",
"favourite":"1",
"family":"Al fakher"
},
{
"name":"Ананас",
"description":"Со вкусом Ананаса",
"rating":"4.1",
"favourite":"1",
"family":"Al fakher"
},
{
"name":"Апельсин",
"description":"Со вкусом Апельсина",
"rating":"4.1",
"favourite":"1",
"family":"Al fakher"
},
{
"name":"Апельсин с мятой",
"description":"Со вкусом Апельсина с мятой",
"rating":"4.1",
"favourite":"1",
"family":"Al fakher"
},
It looks like your json schema issue, i'm guessing listOfTodos return null. You can refer to this to generate your schema.
But sometimes that tools can make us confuse so i tried to create your schema manually like this:
TabakRoot.java
public class TabakRoot {
#SerializedName("tabaksArrayList")
private List<TabakItem> tabakItem = null;
public List<TabakItem> getTabakItem() {
return tabakItem;
}}
TabakItem.java
public class TabakItem {
#SerializedName("family")
#Expose
private String tabakFamily;
public String getTabakFamily() {
return tabakFamily;
}}
finally
TabakRoot listOfTodos = new Gson().fromJson(reader, TabakRoot.class);
List<TabakItem> todoList = listOfTodos.getTabakItem();
Looks like you are not initialising your ArrayList, try changing:
protected ArrayList<Tabak> tabakArrayList;
for:
protected ArrayList<Tabak> tabakArrayList = new ArrayList<>();
Please put your json file in assets folder
use AsyncTask to protect from ANR like situtation
onBackground(){
String json = null;
try {
InputStream stream = activity.getAssets().open("ur_json_file_in_assets_folder.json");
int size = stream.available();
byte[] buffer = new byte[size];
stream.read(buffer);
stream.close();
json = new String(buffer, "UTF-8");
} catch (IOException e) {
e.printStackTrace();
return null;
}
return json;
}
then parse in
onPostExecute(String str){
JsonObject object = new JsonObject(str);
JsonArray arr = object.getJsonArray("tabaksArrayList");
...}
more details at ParseJsonFileAsync.java
You're not initialising tabakArrayList, add a constructor to your ListOfTabaks as following
public ListOfTabaks{
tabakArrayList = new ArrayList<>();
}
and you should be fine
I want to deserialize a JSON response but I'm not sure about the format. The format can vary in each case. For example the response contains a field named "error" which may be false (boolean) or an object that describes the error eg. "error": { "code": xxx , "description":"etc"}
How should I implement a class that covers both cases? Is there any way to do this?
Thanks
I would prefer using a TypeAdapter for your case:
private static class Error {
private boolean hasError;
private int code;
private String description;
}
private static class ErrorTypeAdapter extends TypeAdapter<Error> {
#Override
public Error read(JsonReader jsonReader) throws IOException {
Error response = null;
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String currentJsonName = jsonReader.nextName();
if("error".equals(currentJsonName)) {
response = new Error();
try {
response.hasError = jsonReader.nextBoolean();
} catch (Exception e) {
response.hasError = true;
jsonReader.beginObject();
}
} else if("code".equals(currentJsonName)) {
response.code = jsonReader.nextInt();
} else if ("description".equals(currentJsonName)) {
response.description = jsonReader.nextString();
}
}
if(response.hasError) {
jsonReader.endObject();
}
jsonReader.endObject();
return response;
}
#Override
public void write(JsonWriter jsonWriter, Error response)
throws IOException {
jsonWriter.beginObject();
jsonWriter.name("hasError").value(response.hasError);
jsonWriter.name("code").value(response.code);
jsonWriter.name("description").value(response.description);
jsonWriter.endObject();
}
}
To test it you can use:
String val1 = "{\"error\": {\"code\": 1 , \"description\":\"etc\"}}";
String val2 = "{\"error\": false}";
final GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Error.class, new ErrorTypeAdapter());
gsonBuilder.setPrettyPrinting();
final Gson gson = gsonBuilder.create();
gson.fromJson(val1, Error.class);
gson.fromJson(val2, Error.class);
You can read more about TypeAdapters here and also some great examples here.