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);
Related
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.
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).
I have an object named Item with plenty of fields. I'm using a Java JSON (json-io) library to serialize its state in a File:
String json = JsonWriter.objectToJson(item);
// Write String to File
I'd like to make the json String less verbose so that it does not include null values (if possible also boolean which are false). Is it possible to do it somehow ?
Thanks
I can recommend using jackson mapper if possible.
Check out these two questions:
Jackson serialization: ignore empty values (or null)
How to tell Jackson to ignore a field during serialization if its value is null?
I want to parse json from a server and place it into a class. I use json4s for this. The issue is that a json object contains too many fields, it's about 40-50 of them, some of them have the long names.
I wonder, what will be a sensible way to store all of them, will I have to create 40-50 fields in a class? Remember, some of them will have the long names, as I said earlier.
I use Scala, but a Java's approach might be similar to it, so I added a tag of Java also.
I don't know json4s but in Jersey with Jackson, for example, you can use a Map to hold the Json data or you can use a POJO with all those names.
Sometimes its better to have the names. It makes the code much easier to understand.
Sometimes its better to use a Map. For example, if the field names change from time to time.
If I recall it correctly, using pure Jackson you do something like this:
String jsonString = ....; // This is the string of JSON stuff
JsonFactory factory = new JsonFactory();
ObjectMapper mapper = new ObjectMapper(factory); // A Jackson class
Map<String,Object> data = mapper.readValue(jsonString, HashMap.class);
You can use a TypeReference to make it a little cleaner as regards the generics. Jackson docs tell more about it. There is also more here: StackOverflow: JSON to Map
There are generally two ways of parsing json to object
1) Parse json to object representation.
the other which might suit you as you mention that your object has too many fields is amap/hashtable, or you could just keep it as JObject, an get fields ehrn you need them
It's a kind of odd question for an odd situation. I have a large JSON structure which I would like to represent in running groovy code. I need groovy objects that mirror the same structure as the JSON objects.
As to be expected a web search mostly returns results with groovy/json runtime conversion stuff, but nothing about things that output groovy code.
You might think this lazy but really it is a massive JSON structure! A converter would save days!
You can use Groovy's own JsonSlurper to parse JSON objects:
import groovy.json.*
def json = '{"name":"john", "surname":"doe", "languages": ["groovy", "python"]}'
def obj = new JsonSlurper().parseText(json)
assert obj.name == "john"
assert obj.surname == "doe"
assert obj.languages.containsAll("python", "groovy")
Of course the class is untyped: it's only known at runtime. If you want it to be typed, you can write a code which writes the code based on an example (since a json schema may be rare).
EDIT: if you want to generate the model classes code, you can try JSONGen, which "parses JSON to create client side source files to model the JSON data structure". I'm not aware of a solution for Groovy, but since java-groovy integrations is seamless, it shall work fine.
If you want a Groovy representation of your JSON, you can get that via the built-in JsonSlurper. This will give you Java Maps and Lists of data you can work with.
You can populate more specific, custom objects you've written to represent your JSON entities using the (3rd party) Jackson's data binding functionality (see this question as well).
Try using a JSON parser like this one. According to its documentation you just need to do
JSON.parse
to deserialize the data