I have a HashMap<Picture, String> with Picture being a data-class I created in kotlin. I save the HashMap into the SharedPreferences using gson.toJson(hashmap) and this works fine. But when I try to deserialize the very same string (I checked) into the HashMap<Picture, String> again, it fails with a weird error.
This is the Exception:
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 3 path $.
This is the string for reference:
{
"Picture(image_url\u003dhttps://nftmintapp.infura-ipfs.io/ipfs/QmZnbgRFCvqXeahD37vaRANjPiyF9oCC2aWw1TwHat8SaU, creator_name\u003dmarkus, creator_address\u003d0x0, image_name\u003dethOS3, additional_url\u003dhttps://google.com)":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
The String I save in reference to the String is a Bytearray that I convert to string using Base64.encodeToString(bytes, Base64.NO_WRAP).
I assumed that gson would be able to de-serialize anything it serialized itself, has anybody ever encountered this?
The JSON specification only allows strings as property names of JSON objects. Gson works around this by simply calling the toString() function on Map keys and serializing that as JSON property names. However, for deserialization it uses the standard JSON deserialization logic.
For simple Map keys such as String or Int this works just fine, but for complex key types, such as the Picture class in your case, this leads to undesired behavior.
The solution is to either
restructure your code so it uses a Map<String, ...> and for example stores the picture data as part of the Picture class as well, or have a data class which contains the picture data and the Picture object
or to
use GsonBuilder.enableComplexMapKeySerialization(), see also the user guide for additional information
In case you already have released a version of your app with this faulty JSON serialization logic and you want to preserve backward compatibility, you will have to write a JsonDeserializer (or TypeAdapterFactory, but that is a bit more complicated) which tries to deserialize this faulty JSON value.
Related
I need to convert a certain JSON string to a Java object. I am using Jackson ObjectMapper for reading the JSON. The JSON String is something like this:-
"{"emailId":"gmail#rajnikant.com","accessToken":"accTok"}4".
When I am using objectMapper.readValue() for reading the JSON string to a specific destination class, it should throw an exception because of the JSON string being appended by 4. What should I do so that only valid JSON can be read and in other cases it will throw an exception?
To Jackson, GSON and others, a JSON string with some characters appended after the last } is valid JSON as long as what is contained between the {} is valid JSON.
As stated by a member of FasterXML (Jackson) team:
Yes. This is by design. If you want to catch such problems, you need to construct JsonParser, advance it manually. Existence of multiple root-level values is not considered a validity problem.
Reference: https://github.com/FasterXML/jackson-databind/issues/726
So if you need to enforce "clean" JSON you'll have to extend the default parser with your own functionality. However, IMO if it's OK to the default parser it should be OK to you too (unless we're dealing with some inter-language incompatibility scenario here).
As far as I know, all JSON field names are string values. However, I encountered a code snippet that does a string check on the "keys" of JSON to see if it's a string, and if not, it throws an exception. It goes something like:
if (!(key instanceof String)){
throw new exception();}
Is this check necessary?
EDIT:
For example,
while (jp.nextToken() == JsonToken.FIELD_NAME){
String key = jp.getCurrentName();
}
This code snippet will only progress to JSON tokens that are strings, so I was wondering if a JSON could contain fieldnames that are not strings so that Jackson parser will simply skip those fieldnames.
From the JSON official website (and by proxy, the JSON Data Interchange Standard):
When creating an object, the key must be a String.
EDIT: As #SotiriosDelimanolis pointed out in the comments, this only applies to the format of the JSON file, not necessarily once parsed through a Java library.
Jackson, for example, can deserialize keys into custom types - #SotiriosDelimanolis
I use the Jackson library with Java to serialize POJOs to JSON and vice versa. Let's say that I am running some tests where I am serializing an object and I know that the expected JSON string is {"firstName":"John", "lastName":"Doe"}. What is the best way to validate that my object serialized to the above string? Or better yet, what is the best way to validate that each of the fields is what I expect?
I have tried simply hard coding that string in and doing a comparison, but I have had cases where I serialize to JSON -> deserialize to POJO -> then serialize the deserialized POJO back to JSON again, and the fields are out of order. Then the string comparison fails even though all of the fields are correct.
Is there are better/different way to verify that my JSON string has the expected fields in it when testing?
I ran into the exact same situation as you and found JSONassert to be very helpful.
In your JUnit test you would have to add something like this:
String actual = getSerializedContent();
String expected = "{firstName:\"John\", lastName:\"Doe\"}";
JSONAssert.assertEquals(expected, actual, false);
I have a JSON file with no clue on how data will be in it nor the structure of data.
The only thing known is that it will have either an array of JSON objects or a single JSON object.
I need to get each object from the file and store it as a separate item. In case of array of objects in the file, I should get an array of JSON strings which I can store in DB.
Basically, I need to read this file and separate out each JSON object from it and store it in DB as a string.
One of the ways to do it was to use JACKSON ObjectMapper and assign these items to a Hashmap as key value pairs, but I am not sure though how it can be done If there are list of JSON Objects in the file.
Sample JSON File:
[
{
"name":"Bob",
"type":"Email",
"from":"a#a.com",
"to":"b#B.com",
"attachments":[...],
.
.
.
}
]
Do you know the Object structure that the JSON has(let it be Array or a single one) ? If Yes,
First load the json string form the file into an in memory string.
check the string for Array existence, by searching for '[',']' in the outer structure of multiple occurrences of '{' or '}'
once you know whether you have an array or a single object, you can pass it as object reference to either Jackson or GSON parsers
create in memory Array of JsonObject.class say List. It is actually better to enclose this List inside another class. say myJsonObjects and have a List inside it.
Let us see GSON parsers (by google), though Jackson can also be used in the similar implementation
Gson gson = new Gson();
if(isArray){
myJsonObjects jsonArray = gson.fromJson(jsonStringFromFile,myJsonObjects );
}
else{
gson.fromJson(jsonStringFromFile,JsonObject);
}
http://google-gson.googlecode.com/svn-history/trunk/gson/docs/javadocs/com/google/gson/Gson.html
Jackson is my favorite JSON-to-POJO library. It doesn't really matter where you're loading the JSON from (a URL or from the filesystem), there are handlers for several input sources.
Here's an example:
Map<String,Object> userData = mapper.readValue(new File("user.json"), Map.class);
As far as having an unknown number of JSON structures that you're about to parse, the first thing that comes to mind is to have a mapper for each type you're expecting. You could then wrap the parsing code in try/catch blocks so that if the first fails with whatever exception Jackson gives you when encountering an unexpected format, you can then try the next format and so on.
If you're just trying to generically parse JSON that you don't know the structure of beforehand, you can try something like this:
mapper.readValue(jsonString, new TypeReference<List<EntryType>>() {});
The documentation for Jackson is pretty good-- giving it a solid read-through should definitely help. Here's a good five minute tutorial: http://wiki.fasterxml.com/JacksonInFiveMinutes
I prefer use Gson:
Gson gson;
Map<String, Object>parameters=gson.fromJson(myString);
the rest is iterate the map, i hope help you
I've a problem with storing a Json object as a java object, I'm not sure what structure to use to store something like this:
'tags':[{'CouchDB':1},{'JSON':1},{'database':1},{'NoSQL':1},{'document_database':1}]
I have tried 2 dimensional arrays, ArrayLists and Hashtables but didn't work, could be down to my poor implementation or I just have it wrong, need help with this ASAP please!
I'm using GSON to convert from the Json String to the Java object, and have other parts working fine, the problem is just having GSON parse this structure properly
Try using http://jsonlint.com/ to make sure that your JSON is valid (it doesn't seem to be)
If you change your tags to {"name":"couchdb"}, your Java class could look like this:
public class Tag
{
private String name;
...
}
And your container class could have a private List<Tag> tags;
Seems, like your tags are just a bunch of keys with a count (or something along those lines) attached to each one, i.e. key-value pairs which is just a hashtable e.g.:
{'tags':{'CouchDB':1,'JSON':1,'database':1,'NoSQL':1,'document_database':1}}
You should be able to convert the above without any trouble, if you can't I would say you have some sort of configuration issue as opposed to any kind of problem with the format of the data.