Continue processing when an Exception occurs - java

I have the below code that basically reads a bunch of JSON strings, and converts them to a java object. My problem is if at any point, the transformation fails for any of the JSON strings, it doesn't process the others strings. What I need is -
Find the string for which the error occured.
In the exception block do something to continue processing.
Here is my code to convert from JSON to Java.
public static <T> T convertToObject(String jsonString,Class<T> classType){
T obj = null;
try {
obj = objectMapper.readValue(jsonString, classType);
} catch (Exception e) {
throw new Exception("Unable to convert to DTO :" + e.getMessage(), e);
}
return obj;
}

I think you need a custom deserializer. Standard ObjectMapper will do all or nothing. Read more about creating a custom deserializer for Jackson ObjectMapper here:
http://www.baeldung.com/jackson-deserialization

Related

How to concatenate 2 different types of streams using Smallrye Mutiny Multi?

I would like to concatenate 2 OutputStream of different types using the method Multi.createBy().concatenating().streams. Is there a way to achieve this?
I have 2 streams one is of ByteArrayOutputStream and other is of custom type CustomerEvent and I would like to concatenate them using the SmallRye Mutiny. Is there a way to achieve this?
public class CustomerGenerator {
private ByteArrayOutputStream jsonOutput;
private JsonGenerator jsonGenerator;
private CustomerGenerator() {
try {
jsonOutput = new ByteArrayOutputStream();
jsonGenerator = new JsonFactory().createGenerator(jsonOutput).useDefaultPrettyPrinter();
} catch (IOException ex) {
throw new CustomerGeneratorException("Exception occurred during the generation of customer document : " + ex);
}
}
public Multi < Customer > generateCustomer(final Input input) {
try {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("type", "customerDocument");
jsonGenerator.writeStringField("creationDate", Instant.now().toString());
jsonGenerator.writeFieldName("customerBody");
jsonGenerator.writeStartObject();
jsonGenerator.writeFieldName("customerList");
jsonGenerator.writeEndObject(); // End body
jsonGenerator.writeEndObject(); // End whole json file
Multi < ByteArrayOutputStream > jsonWrapper = Multi.createFrom().item(jsonOutput);
return Multi.createBy().concatenating().streams(jsonWrapper, Multi.createFrom().publisher(new CustomerPublisher(input))));
} catch (IOException ex) {
throw new CustomerGeneratorException("Exception occurred during customer document wrapper creation : " + ex);
}
}
}
As you can see from the code sample, I would like to concatenate the generated JSON to my other JSON of type Customer. Is there a way to achieve this?
Multi < ByteArrayOutputStream > jsonWrapper = Multi.createFrom().item(jsonOutput);
return Multi.createBy().concatenating().streams(jsonWrapper, Multi.createFrom().publisher(new CustomerPublisher(input))));
Both Multi have to return a Multi<Customer> if you want to concatenate them.
Looking at your code, it seems that what you need to do is to convert the json into a Customer (or collection of Customer) and then convert it to a Multi. I don't know how you convert the JSON to a Customer, assuming you have a function convertToCustomer, this is how the code should look like:
Multi<Customer> customerMulti = Multi.createFrom().item( convertToCustomer(jsonGenerator))
Multi<Customer> customersPublisher = Multi.createFrom().publisher(new CustomerPublisher(input));
// Now you can concatenate the two
Multi<Customer> result = Multi.createBy().concatenating()
.streams(customerMulti, customersPublisher);
Alternatively, your method could return a Multi<Object>. But I suspect this is not what you need.

How to fix 'JsonNull cannot be cast to JsonObject'

I call a post API which responds with details on specific addresses, however some of the responses that get returned have no data so they'll be returned as null. How do I stop the casting error in my code?
I currently only get the data as a Json Object and I'm not sure how to rework my code that so when a JsonNull Element gets returned I can handle that data.
JsonElement element = new JsonParser().parse(jsonString);
JsonObject jsonObject = element.getAsJsonObject();
jsonObject = jsonObject.getAsJsonObject("response"); // This is either an object or it is null
String buildName = jsonObject.get("buildingName").getAsString();
String buildNum = jsonObject.get("premisesNumber").getAsString();
String streetName = jsonObject.get("streetName").getAsString();
What I expect to be returned would be either the address details for valid addresses or no information at all for the invalid addresses.
The error that gets produced is this:
java.lang.ClassCastException: com.google.gson.JsonNull cannot be cast to com.google.gson.JsonObject
Before getAsString() check for isJsonNull(). It'll return true if object is Null.
You can rewrite your code as below
String buildName= (jsonObject.get("buildingName").isJsonNull ? null : jsonObject.get("buildingName").getAsString());
Normally is a good idea validate the data is JSON valid
public static boolean isJSONValid(String test) {
try {
new JSONObject(test);
} catch (JSONException ex) {
try {
new JSONArray(test);
} catch (JSONException ex1) {
return false;
}
}
return true;
}
Function above will return you true in case the string is a valid JSON object(could be an object or an array of objects).
After that you can continue parsing using Jackson lib or the GSON lib

Unable to load class exception during Kryo deserialization

I am using Kryo for serialization / deserialization and not registering classes beforehand (I am working on that). That said, upon deserialization, I am getting the exception:
Unable to load class shell.api.model.BatteryStatuo with kryo's ClassLoader. Retrying with current..
Now, my classname is actually shell.api.model.BatteryStatus so I'm not sure what happened during serialization.
Is there a limitation on the length of the classname?
Also, as I am serializing JPA entities which have nested structures and likely have circular references, will that pose a potential issue? I would think I'd see a stack overflow exception if so.
This is a snippet of serializing an object:
protected final Kryo kryo = new Kryo();
try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
try (final Output output = new Output(baos)) {
kryo.writeObject(output, data);
}
return (baos.toByteArray());
} catch (IOException e) {
LOGGER.error("error serializing", e);
throw (new RuntimeException("Error serializing", e));
}
deserialization:
try (final Input input = new Input(inputStream)) {
return ((Serializable) kryo.readObject(input, entityType));
}
entityType is the parent class, in this case:
shell.api.model.Heartbeat
and, inside Heartbeat are several entities, one of which is BatteryStatus.
Kryo can handle serializing and deserializing complex nested objects and circular references. It's part of the reason why so many people love Kryo!
Since the object you are sending could be one of many possible types you should use the writeClassAndObject and readClassAndObject methods.
protected final Kryo kryo = new Kryo();
try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
try (final Output output = new Output(baos)) {
kryo.writeClassAndObject(output, data);
return (baos.toByteArray());
} catch (IOException e) {
LOGGER.error("error serializing", e);
throw (new RuntimeException("Error serializing", e));
}
And
try (final Input input = new Input(inputStream)) {
return ((Serializable) kryo.readClassAndObject(input));
}
Docs here
One other possibility is you are using two different versions of Kryo jar in your project and different version classes are being used in serialization and deserialization.

Android - Parsing a JSON string

I'm trying to parse a simple JSON string
try {
String candyJson = "{\"candies\":[ {\"name\":\"Jelly Beans\", \"count\":10}, {\"name\":\"Butterscotch\", \"count\":6}]}";
JSONObject candiesJSONobject = new JSONObject(candyJson);
JSONArray candiesJSONarray = candiesJSONobject.getJSONArray("candies");
Log.v("JSONObject", candiesJSONarray.getJSONObject(0).getString("name"));
} catch (JSONException e){
Log.e("MYAPP", e.toString());
}
The code works fine in this state without catching any exception and prints JSONObject name in the Android Log.
However when I don't try to catch the exception as shown in the following example:
String candyJson = "{\"candies\":[ {\"name\":\"Jelly Beans\", \"count\":10}, {\"name\":\"Butterscotch\", \"count\":6}]}";
JSONObject candiesJSONobject = new JSONObject(candyJson);
JSONArray candiesJSONarray = candiesJSONobject.getJSONArray("candies");
Log.v("JSONObject", candiesJSONarray.getJSONObject(0).getString("name"));
Android Studio gives me unhandled exception error on all JSON methods. Is it necessary to catch JSONException when parsing a JSON or am I doing something wrong?
This is a Java feature actually :-) Please read more about it here.
The idea is that - if a method states that it will throw an (non-Runtime) Exception, all the calls of that method are required to catch this exception, just in case.
It does not mean that you are getting this exception in your code, you can only see that when you actually run it. But Java requires you to be prepared for a situation where such exception is thrown.
Well since you're working with the org.json... json objects, yes most of their methods do throw exceptions that you must catch and handle.
However if you don't want to handle each exception on it's own i suggest you create a json utils class that will handle those things for you.
For example for the JSONObject constructor you can make your own method like so
public static JSONObject createObjectFromString(String objectString) {
try {
return new JSONObject(objectString);
} catch (JSONException e) {
Log.e("MYAPP", e.toString());
}
}
and just reuse this method when you want to create a new json object.
Yes actually if any method is throwing Exception you need to catch that Exception.
This is called as Checked Exceptions or Compile Time Exceptions.
In your case methods like
JsonArray getJsonArray(String name)
or
JsonObject getJsonObject(String name)
check here http://docs.oracle.com/javaee/7/api/javax/json/JsonObject.html#getJsonArray-java.lang.String-
are throwing ClassCastException So you either catch it or throw the exception.
Throwing Exception will lead to crash the app, So better Catch it.
If any method throws checked Exception, then caller can either handle this exception by catching it or can re throw it by declaring another throws clause in method declaration.
This is the reason Android Studio is showing unhandled exception error.

How to check whether a given string is valid JSON in Java

How do I validate a JSON string in Java? Or could I parse it using regular expressions?
A wild idea, try parsing it and catch the exception:
import org.json.*;
public boolean isJSONValid(String test) {
try {
new JSONObject(test);
} catch (JSONException ex) {
// edited, to include #Arthur's comment
// e.g. in case JSONArray is valid as well...
try {
new JSONArray(test);
} catch (JSONException ex1) {
return false;
}
}
return true;
}
This code uses org.json JSON API implementation that is available on github, in maven and partially on Android.
JACKSON Library
One option would be to use Jackson library. First import the latest version (now is):
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.0</version>
</dependency>
Then, you can implement the correct answer as follows:
import com.fasterxml.jackson.databind.ObjectMapper;
public final class JSONUtils {
private JSONUtils(){}
public static boolean isJSONValid(String jsonInString ) {
try {
final ObjectMapper mapper = new ObjectMapper();
mapper.readTree(jsonInString);
return true;
} catch (IOException e) {
return false;
}
}
}
Google GSON option
Another option is to use Google Gson. Import the dependency:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.5</version>
</dependency>
Again, you can implement the proposed solution as:
import com.google.gson.Gson;
public final class JSONUtils {
private static final Gson gson = new Gson();
private JSONUtils(){}
public static boolean isJSONValid(String jsonInString) {
try {
gson.fromJson(jsonInString, Object.class);
return true;
} catch(com.google.gson.JsonSyntaxException ex) {
return false;
}
}
}
A simple test follows here:
//A valid JSON String to parse.
String validJsonString = "{ \"developers\": [{ \"firstName\":\"Linus\" , \"lastName\":\"Torvalds\" }, " +
"{ \"firstName\":\"John\" , \"lastName\":\"von Neumann\" } ]}";
// Invalid String with a missing parenthesis at the beginning.
String invalidJsonString = "\"developers\": [ \"firstName\":\"Linus\" , \"lastName\":\"Torvalds\" }, " +
"{ \"firstName\":\"John\" , \"lastName\":\"von Neumann\" } ]}";
boolean firstStringValid = JSONUtils.isJSONValid(validJsonString); //true
boolean secondStringValid = JSONUtils.isJSONValid(invalidJsonString); //false
Please, observe that there could be a "minor" issue due to trailing commas that will be fixed in release 3.0.0.
With Google Gson you can use JsonParser:
import com.google.gson.JsonParser;
JsonParser parser = new JsonParser();
parser.parse(json_string); // throws JsonSyntaxException
You could use the .mayBeJSON(String str) available in the JSONUtils library.
It depends on what you are trying to prove with your validation.
Certainly parsing the json as others have suggested is better than using regexes, because the grammar of json is more complicated than can be represented with just regexes.
If the json will only ever be parsed by your java code, then use the same parser to validate it.
But just parsing won't necessarily tell you if it will be accepted in other environments. e.g.
many parsers ignore trailing commas in an object or array, but old versions of IE can fail when they hit a trailing comma.
Other parsers may accept a trailing comma, but add an undefined/null entry after it.
Some parsers may allow unquoted property names.
Some parsers may react differently to non-ASCII characters in strings.
If your validation needs to be very thorough, you could:
try different parsers until you find one that fails on all the corner cases I mentioned above
or you could probably run jsonlint using javax.script.*,
http://npmjs.org/package/jsonlint
or combine using a parser with running jshint using javax.script.*.
https://www.npmjs.org/package/jshint
https://github.com/webjars/jshint
A bit about parsing:
Json, and in fact all languages, use a grammar which is a set of rules that can be used as substitutions. in order to parse json, you need to basically work out those substitutions in reverse
Json is a context free grammar, meaning you can have infinitely nested objects/arrays and the json would still be valid. regex only handles regular grammars (hence the 'reg' in the name), which is a subset of context free grammars that doesn't allow infinite nesting, so it's impossible to use only regex to parse all valid json. you could use a complicated set of regex's and loops with the assumption that nobody will nest past say, 100 levels deep, but it would still be very difficult.
if you ARE up for writing your own parser
you could make a recursive descent parser after you work out the grammar
String jsonInput = "{\"mob no\":\"9846716175\"}";//Read input Here
JSONReader reader = new JSONValidatingReader();
Object result = reader.read(jsonInput);
System.out.println("Validation Success !!");
Please download stringtree-json library
Here is a working example for strict json parsing with gson library:
public static JsonElement parseStrict(String json) {
// throws on almost any non-valid json
return new Gson().getAdapter(JsonElement.class).fromJson(json);
}
See also my other detailed answer in How to check if JSON is valid in Java using GSON with more info and extended test case with various non-valid examples.
The answers are partially correct. I also faced the same problem. Parsing the json and checking for exception seems the usual way but the solution fails for the input json something like
{"outputValueSchemaFormat": "","sortByIndexInRecord": 0,"sortOrder":847874874387209"descending"}kajhfsadkjh
As you can see the json is invalid as there are trailing garbage characters. But if you try to parse the above json using jackson or gson then you will get the parsed map of the valid json and garbage trailing characters are ignored. Which is not the required solution when you are using the parser for checking json validity.
For solution to this problem see here.
PS: This question was asked and answered by me.
Check whether a given string is valid JSON in Kotlin. I Converted answer of MByD Java to Kotlin
fun isJSONValid(test: String): Boolean {
try {
JSONObject(test);
} catch (ex: JSONException) {
try {
JSONArray(test);
} catch (ex1: JSONException) {
return false;
}
}
return true;
}
A solution using the javax.json library:
import javax.json.*;
public boolean isTextJson(String text) {
try {
Json.createReader(new StringReader(text)).readObject();
} catch (JsonException ex) {
try {
Json.createReader(new StringReader(text)).readArray();
} catch (JsonException ex2) {
return false;
}
}
return true;
}
As you can see, there is a lot of solutions, they mainly parse the JSON to check it and at the end you will have to parse it to be sure.
But, depending on the context, you may improve the performances with a pre-check.
What I do when I call APIs, is just checking that the first character is '{' and the last is '}'. If it's not the case, I don't bother creating a parser.
Here you can find a tool that can validate a JSON file, or you could just deserialize your JSON file with any JSON library and if the operation is successful then it should be valid (google-json for example that will throw an exception if the input it is parsing is not valid JSON).
Using Playframework 2.6, the Json library found in the java api can also be used to simply parse the string. The string can either be a json element of json array. Since the returned value is not of importance here we just catch the parse error to determine that the string is a correct json string or not.
import play.libs.Json;
public static Boolean isValidJson(String value) {
try{
Json.parse(value);
return true;
} catch(final Exception e){
return false;
}
}
IMHO, the most elegant way is using the Java API for JSON Processing (JSON-P), one of the JavaEE standards that conforms to the JSR 374.
try(StringReader sr = new StringReader(jsonStrn)) {
Json.createReader(sr).readObject();
} catch(JsonParsingException e) {
System.out.println("The given string is not a valid json");
e.printStackTrace();
}
Using Maven, add the dependency on JSON-P:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.4</version>
</dependency>
Visit the JSON-P official page for more informations.
in Gson Version
try {
String errorBody = response.errorBody().string();
MyErrorResponse errorResponse = new Gson().fromJson(errorBody, MyErrorResponse.class);
} catch (JsonSyntaxException e) {
e.printStackTrace();
}
I have found a very simple solution for it.
Please first install this library net.sf.json-lib for it.
import net.sf.json.JSONException;
import net.sf.json.JSONSerializer;
private static boolean isValidJson(String jsonStr) {
boolean isValid = false;
try {
JSONSerializer.toJSON(jsonStr);
isValid = true;
} catch (JSONException je) {
isValid = false;
}
return isValid;
}
public static void testJson() {
String vjson = "{\"employees\": [{ \"firstName\":\"John\" , \"lastName\":\"Doe\" },{ \"firstName\":\"Anna\" , \"lastName\":\"Smith\" },{ \"firstName\":\"Peter\" , \"lastName\":\"Jones\" }]}";
String ivjson = "{\"employees\": [{ \"firstName\":\"John\" ,, \"lastName\":\"Doe\" },{ \"firstName\":\"Anna\" , \"lastName\":\"Smith\" },{ \"firstName\":\"Peter\" , \"lastName\":\"Jones\" }]}";
System.out.println(""+isValidJson(vjson)); // true
System.out.println(""+isValidJson(ivjson)); // false
}
Done. Enjoy
import static net.minidev.json.JSONValue.isValidJson;
and then call this function passing in your JSON String :)
public static boolean isJSONValid(String test) {
try {
isValidJSON(test);
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(test);
while (!parser.isClosed()) {
parser.nextToken();
}
} catch (Exception e) {
LOGGER.error("exception: ", e);
return false;
}
return true;
}
private static void isValidJSON(String test) {
try {
new JSONObject(test);
} catch (JSONException ex) {
try {
LOGGER.error("exception: ", ex);
new JSONArray(test);
} catch (JSONException ex1) {
LOGGER.error("exception: ", ex1);
throw new Exception("Invalid JSON.");
}
}
}
Above solution covers both the scenarios:
duplicate key
mismatched quotes or missing parentheses etc.
You can try below code, worked for me:
import org.json.JSONObject;
import org.json.JSONTokener;
public static JSONObject parseJsonObject(String substring)
{
return new JSONObject(new JSONTokener(substring));
}

Categories

Resources