JSONArray to ArrayList in Android - java

I get jsonarray as following from server "dataArray":
[{"FirstNmae":"xyz","BranchId":"asd","Location":"qwe"}]
Now I want to create ArrayList<EmpData> list using Gson where EmpData is normal Pojo class. Below is my code which is getting error
TypeToken<List<EmpData>> token = new TypeToken<List<EmpData>>() {};
List<EmpData> empList = gson.fromJson(dataArray, token.getType());

Not an answer, but included as an answer to show formatted code.
Unable to reproduce. Here is a Minimal, Reproducible Example, based on the information in the question, and it runs fine.
The code uses public fields for simplicity. Real code would likely use private fields and getter/setter methods, but since the POJO is not the question, I kept this simple.
Gson gson = new Gson();
// Code from question starts here
String dataArray = "[{\"FirstNmae\":\"xyz\",\"BranchId\":\"asd\",\"Location\":\"qwe\"}]";
TypeToken<List<EmpData>> token = new TypeToken<List<EmpData>>() {};
List<EmpData> empList = gson.fromJson(dataArray, token.getType());
// Code from question ends here
System.out.println("dataArray = " + dataArray);
System.out.println("empList = " + empList);
class EmpData {
#SerializedName("FirstNmae")
public String firstName;
#SerializedName("BranchId")
public String branchId;
#SerializedName("Location")
public String location;
#Override
public String toString() {
return "EmpData[firstName=" + this.firstName +
", branchId=" + this.branchId +
", location=" + this.location + "]";
}
}
Output
dataArray = [{"FirstNmae":"xyz","BranchId":"asd","Location":"qwe"}]
empList = [EmpData[firstName=xyz, branchId=asd, location=qwe]]
Notice how the #SerializedName annotation is used to handle the typo in the name (FirstNmae), as well as the uppercase/lowercase issue of the first letter in the names.

Related

Obtain specific part of a string with JSON Format java

I have a question on how would be the best way to get the information from a string but that has JSON format.
{
"internal_id":"1234",
"moreInformation":"Failed authentication for user."
}
In this case, I want to get the value of "internal_id" and I already did, with subtring, lastIndexOf and indexOf
public static String returnInternalCode(String json){
String internalCode = json.substring(json.lastIndexOf("\"internal_id\":\"") + "\"internal_id\":\"".length(), json.length() - 1);
if (json.lastIndexOf("\"internal_id\":\"") == -1) return null;
return internalCode.substring(0, internalCode.indexOf("\""));
}
I also tried several JSONs with order changes that don't have the data and it also worked. I leave the full class of tests I did:
public class Test {
public static void main(String[] args) {
// Original JSON
String json = "{\"internal_id\":\"999999\",\"moreInformation\":\"Failed authentication for user, 1 authentication attempt remaining.\"}";
// Other JSON order
String json2 = "{\"moreInformation\":\"Failed authentication for user. Invalid response.\", \"moreInformation2\":\"Failed authentication for user. \", \"internal_id\":\"45678\"}";
// JSON without the internal_id
String json3 = "{\"moreInformation\":\"Failed authentication for user. Invalid response.\"}";
// JSON without moreInformation
String json4 = "{\"internal_id\":\"999999\"}";
System.out.println("JSON: ".concat(json4));
System.out.println("internalId: " + returnInternalId(json4));
System.out.println("moreInformation: " + returnMoreInformation(json4));
}
public static String returnInternalId(String json){
String internalCode = json.substring(json.lastIndexOf("\"internal_id\":\"") + "\"internal_id\":\"".length(), json.length());
if (json.lastIndexOf("\"internal_id\":\"") == -1) return null;
return internalCode.substring(0, internalCode.indexOf("\""));
}
public static String returnMoreInformation(String json){
String moreInformation = (json.substring(json.lastIndexOf("\"moreInformation\":\"") + "\"moreInformation\":\"".length(), json.length()));
if (json.lastIndexOf("\"moreInformation\":\"") == -1) return null;
return moreInformation.substring(0, moreInformation.indexOf("\""));
}
}
I would like to know if there are better ways to do what I did, such as with StringBuilder or StringBuffer and also to find out which way uses less memory or is faster to run, how do I know that? How long does it take to execute a method?
Thank you very much!
You can extract the values this way; Using Simple-json library
JSONObject jobj = (JSONObject) parser.parse(yourJsonString); // Pass the Json formatted String
String internal_id = (String) jobj.get("internal_id"); // Extract the value from your key
System.out.println(internal_id); // 1234

POJO with array of integers to deserialize

I am having some trouble deserializing the following JSON into a POJO. I have no control over the JSON structure, else I would've implemented it in some other way, but, that's life for you.
{
"1":{
"test":"1",
"other":"stuff"
},
"2":{
"test":"2",
"other":"stuff2"
}
}
Anyway, I am trying to deserialize by using a POJO with:
public Map<Integer, Payload> payload;
but although the Map does have a size of 2, when I try to get each of it, it's contents are null. Any idea on what I am doing wrong?
Thank you
I have no idea how the payload class looks like, but it should be something like this:
class Payload {
String test;
String other;
#Override
public String toString() {
return "Payload [test=" + test + ", other=" + other + "]";
}
}
If you assert this condition, then you can deserialize the json using a TypeToken> as token as danypata suggest... like:
public static void main(String args[]) throws InterruptedException {
String ff = "{\"1\":{" + "\"test\":\"1\"," + "\"other\":\"stuff\"" + "}," + "\"2\":{" + "\"test\":\"2\","
+ "\"other\":\"stuff2\"" + "}}";
Gson gson = new Gson();
Type mapType = new TypeToken<Map<String, Payload>>() {
}.getType();
Map<String, Payload> map = gson.fromJson(ff, mapType);
System.out.println(map);
for (Entry<String, Payload> entry : map.entrySet()) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
}
giving as result:
{1=Payload [test=1, other=stuff], 2=Payload [test=2, other=stuff2]}
1
Payload [test=1, other=stuff]
2
Payload [test=2, other=stuff2]
Why don't you use the Android JSONObject class? Then you can parse with it your entire JSON string and then you can obtain the values easily. For example this is to get the values of your "1" JSON object:
final JSONObject jsonObject = new JSONObject(jsonString);
final String test = jsonObject.getJSONObject("1").getString("test");
final String other = jsonObject.getJSONObject("1").getString("other");

How to get an Enum value from a Multimap

Here is my enum:
public enum StaffRanks {
HELPER("helpers"),
MODERATOR("moderators"),
ADMINISTRATOR("administrators"),
DEVELOPER("developers"),
OWNER("owners");
private String name;
StaffRanks(String name) {
this.setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
This is how I create my Multimap:
public static Multimap<String, StaffRanks> staffMembers;
public static void fetchPlayerRanks() {
JsonParser parser = new JsonParser();
try {
Object obj = parser.parse(new FileReader(".\\Data\\staff_list.json"));
JsonObject staffList = (JsonObject) obj;
Type listType = new TypeToken<List<String>>() {
}.getType();
staffMembers = ArrayListMultimap.create();
for (StaffRanks rank : StaffRanks.values()) {
staffMembers.put(new Gson().fromJson(staffList.get(rank.getName()), listType), rank);
}
} catch (Exception e) {
e.printStackTrace();
}
}
And this is how I want to use it:
int index = 39550;
for (String player : allStaffNames) {
onlineStatus = "#red#Offline";
if (onlineStaff.contains(PlayerHandler.getPlayer(player))) {
onlineStatus = "#gre#Online";
}
if (staffMembers.containsKey(player)) {
playerClient.getPA().sendFrame126("[" + staffMembers.get(player).getName() + "]#cya#" + Misc.formatPlayerName(player) + ": ", index);
}
playerClient.getPA().sendFrame126(onlineStatus, index - 1);
index += 2;
}
Now, the question is: how I can get the name from the enum inside the Multimap?
Here is what I tried. But, it didn't work.
staffMembers.get(player).getName()
Here is what the Staff_list.json file looks like:
{
"owners":['chuck'],
"developers":['tyrant','stan'],
"serverManagers":['logical'],
"staffManagers":['bench press', 'bench press2'],
"communityManagers":['cleave'],
"administrators":['zeven', 'reavers', 'redaeran', 'stuart'],
"moderators":['searwen', 'potentials', 'maud', 'lickylicky'],
"helpers":['megafun12', 'rhysj', 'vaping', 'punch']
}
Because staffMembers is defined as Multimap<String, StaffRanks>, it means that you should read this as Map<String, Collection<StaffRanks>> with shiny Guava interface for such case (i.e. mapping key to a collection of values). So in your case what you're actually trying to do is:
Collection<StaffRanks> staffRanksForPlayer = staffMembers.get(player);
staffRanksForPlayer.getName(); // BOOM!
If you read / attached an error message, it would be much easier. Anyway, you have two options here:
You're using wrong collection type because you want Map<String, StaffRank> if one player can have only one rank - if so, change collection to Map and you're good.
You have to find a matching rank somehow or use all of them in your code. For example, the latter could be achieved with Java 8:
List<String> staffRanksNamesForPlayer = staffMembers.get(player).stream()
.map(StaffRanks::getName)
.collect(Collectors.toList());
// use list's `toString()` in your code to print its contents
playerClient.getPA().sendFrame126("[" + staffRanksNamesForPlayer.toString()
+ "]#cya#" + Misc.formatPlayerName(player) + ": ", index);
One more thing: generally you want to specify which specific Multimap interface you're using: ListMultimap or SetMultimap.

With GSON, is it possible to get a list of fields in an HashMap

I have the following class:
public class Address {
String customerName;
String emailAddress;
String address1;
int age;
double height;
// .. etc, including getters and setters
}
would it be possible to get an HashMap of those fields somehow? For instance, String name = address.getFields("customerName");. It would make validation a lot easier.
Yes, you should be able to with the following class definition:
public class Address extends HashMap<String, Object>{
}
Then to use it:
String jsonString = "{\n"
+ " \"customerName\":\"John\",\n"
+ " \"emailAddress\":\"john#fake.com\",\n"
+ " \"address1\":\"Fake St.\",\n"
+ " \"age\": 20,\n"
+ " \"height\": 5\n"
+ "}";
Gson gson = new Gson();
Address address = gson.fromJson(jsonString, Address.class);
String name = (String)address.get("customerName"); // John
int age = (int)address.get("age"); // 5
Now, using Gson deserialization this way isn't as useful and it's more useful with the POJO you originally created.
Although, there are some instances where using a Map might be more beneficial such as random key/value pairs that you can iterate over.

Java - Parsing JSON Response - Content is either String or JSONObject

I am facing a typical scenario while parsing JSON Response for one of the Service calls.
The content for one of the attributes (from below example, consider "name" as a attribute) coming as either String or JSONObject.
How to handle these kind of scenarios through code. Also, please consider that json content need not be consistent with same set of attributes.
Example:
String Response
{"name":"Adam"}
JSON Response
{"name":{"FirstName":"Adam", "MiddleName":"Don"} }
OR
{"name":{"FirstName":"Adam", "LastName":"Don"} }
OR
{"name":{"MiddleName":"Adam", "LastName":"Don"} }
You can ask the root JSONObject with the method optJSONObject(name) to return a JSONObject for the given name if it exists and is an JsonObject. Otherwise you can also test with optString(name) for a String.
So something like:
JSONObject root = new JSONObject(... data from server ... );
JSONObject obj = root.optJSONObject("name");
if (obj != null) {
// Do something with the object
} else {
String name = root.getString("name");
// Do something with the string
}
Parse your response JSON as a JSONObject, then get another JSONObject for the "name" key, if it throws a JSONException then your object is probably a String in with case you can call get String for the "name" key in your catch block.
String name = "";
JSONObject serverJSON = new JSONObject(YOUR_JSON_RESPONSE_STRING_FROM_SERVER);
try {
JSONObject nameObject = serverJSON.getJSONObject("name");
if (nameObject.has("first_name")) {
name = nameObject.getString("first_name") + " ";
}
if (nameObject.has("middle_name")) {
name += nameObject.getString("middle_name") + " ";
}
if (nameObject.has("last_name")) {
name += nameObject.getString("last_name");
}
name = name.trim();
} catch (JSONException e) {
// Probably a String, try again...
try {
name = serverJSON.getString("name");
catch (JSONException e) {
// Not a String or a JSONObject... figure out what's wrong...
e.printStackTrace();
}
}
I would really recommend though, that if you have any control of the server that you make sure that the name key choose one type and sticks to it; a JSONObject... You would be able to use the has(String key) member function in if statements to properly find all of your data without knowing what existed at runtime...
EDIT: Thought of a different idea... Parse the String to the first colon and see if the next non-whitespace character is a quotation mark, if it is, then your key belongs to a String, if it is a curly brace then it's a JSONObject. (If neither, then you have an error, because you aren't expecting an array or number or null or anything else...)
boolean jsonIsString = true;
String searchString = json.substring(json.indexOf(":")).trim();
if ("{".equals(searchString.charAt(0)) {
jsonIsString = false;
}
Tonity's solution is good. You can also use this solution.
In my solution, there will be no any Exception fired until JSON is wrong. What I am doing is following.
Search for number of ":" in string.
If it returns 1, then we sure that there is "name" value.
Otherwise, we need to check, whether there is "FirstName","MiddleName" or "LastName" exist in string or not.
Just go through this snippet and you will find solution for your problem.
// String str = "{\"name\":\"chintan\"}";
String str = "{\"name\":{\"FirstName\":\"Chintan\",\"LastName\":\"Rathod\"}}";
try {
//we will check how many ":" are there in string, if it is one, then
// we are going to get "name" field.
if ((str.split(":").length - 1) == 1)
{
Log.d("Home", "1");
JSONObject json = new JSONObject(str);
Log.d("Home", "Name : " + json.get("name"));
}
else
{
Log.d("Home", "more then 2");
JSONObject jName = new JSONObject(str);
JSONObject jTemp = jName.getJSONObject("name");
if (jTemp.toString().contains("FirstName"))
Log.d("Home", "FirstName :" + jTemp.getString("FirstName"));
if (jTemp.toString().contains("MiddleName"))
Log.d("Home","MiddleName :" +jTemp.getString("MiddleName"));
if (jTemp.toString().contains("LastName"))
Log.d("Home", "LastName :" + jTemp.getString("LastName"));
}
} catch (JSONException e) {
e.printStackTrace();
}
Output
08-06 11:52:34.060: D/Home(1439): more then 2
08-06 11:52:34.060: D/Home(1439): FirstName :Chintan
08-06 11:52:34.070: D/Home(1439): LastName :Rathod
I faced a problem like this as well. I didn't want to parse the JSON manually. Do this if firstName exists otherwise do that. I didn't want to mess up my structure because I only define java object and my client handles the parsing. So, I came up with following:
#Getter
#Setter
#ToString
class Response {
private Name name;
#Getter
#Setter
#NoArgsConstructor
#ToString
public static class Name {
private String name;
private String firstName;
private String middleName;
private String lastName;
public Name(String name) {
this.name = name;
}
}
}
Then, parse the json;
ObjectMapper objectMapper = new ObjectMapper();
Response response = objectMapper.readValue(json, Response.class);
Now, string response and JSON response can be parsed with the same class.

Categories