How to Validate JSON with Jackson JSON - java

I am trying to use Jackson JSON take a string and determine if it is valid JSON. Can anyone suggest a code sample to use (Java)?

Not sure what your use case for this is, but this should do it:
public boolean isValidJSON(final String json) {
boolean valid = false;
try {
final JsonParser parser = new ObjectMapper().getJsonFactory()
.createJsonParser(json);
while (parser.nextToken() != null) {
}
valid = true;
} catch (JsonParseException jpe) {
jpe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
return valid;
}

Although Perception's answer probably will fit many needs, there are some problems it won't catch, one of them is duplicate keys, consider the following example:
String json = "{ \"foo\" : \"bar\", \"foo\" : \"baz\" }";
As a complement, you can check for duplicate keys with the following code:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);
objectMapper.readTree(json);
It throws JsonProcessingException on duplicate key or other error.

With Jackson I use this function:
public static boolean isValidJSON(final String json) throws IOException {
boolean valid = true;
try{
objectMapper.readTree(json);
} catch(JsonProcessingException e){
valid = false;
}
return valid;
}

I would recommend using Bean Validation API separately: that is, first bind data to a POJO, then validate POJO. Data format level Schemas are in my opinion not very useful: one usually still has to validate higher level concerns, and schema languages themselves are clumsy, esp. ones that use format being validated (XML Schema and JSON Schema both have this basic flaw).
Doing this makes code more modular, reusable, and separates concerns (serialization, data validation).
But I would actually go one step further, and suggest you have a look at DropWizard -- it integrates Jackson and Validation API implementation (from Hibernate project).

private boolean isValidJson(String json) {
try {
objectMapper.readTree(json);
} catch (JsonProcessingException e) {
return false;
}
return true;
}

Another option would be using java.util.Optional in Java 8. This allows to return an object and to use in the calling code a more functional approach.
This is another possible implementation:
public Optional<JsonProcessingException> validateJson(final String json) {
try{
objectMapper.readTree(json);
return Optional.empty();
} catch(JsonProcessingException e){
return Optional.of(e);
} catch(IOException e) {
throw new RuntimeException(e);
}
}
Then you can use this method like this:
jsonHelper.validateJson(mappingData.getMetadataJson())
.map(e -> String.format("Error: %s at %s", e.getMessage(), e.getLocation().toString()))
.orElse("Valid JSON");

Inproving the other answers
public static boolean isValidJSON(final String json) throws IOException {
boolean valid = true;
try{
mapper.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);
mapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);
objectMapper.readTree(json);
} catch(JsonProcessingException e){
valid = false;
}
return valid;
}

Related

How can I write an XML string in Stax without duplicating namespaces

Part way through creating an XML file with Stax I have some XML in the form of a String. I write this to the Stax output using:
public void addInnerXml(String xml) throws TinyException {
try {
parent.adjustStack(this);
XMLStreamReader2 sr = (XMLStreamReader2) ifact.createXMLStreamReader(new ByteArrayInputStream(xml.getBytes("UTF8")));
for (int type = sr.getEventType(); sr.hasNext(); type = sr.next()) {
switch (type) {
case XMLStreamConstants.COMMENT:
case XMLStreamConstants.DTD:
case XMLStreamConstants.START_DOCUMENT:
case XMLStreamConstants.END_DOCUMENT:
continue;
}
parent.getWriter().copyEventFromReader(sr, false);
}
sr.close();
} catch (XMLStreamException e) {
throw new TinyException("addInnerXml", e);
} catch (UnsupportedEncodingException e) {
throw new TinyException("addInnerXml", e);
}
}
It all works great except namespaces used in the passed in XML, that are defined in the root element, are duplicated again in the inner nodes. Note that the p prefix is repeated
<p:sld xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
<p:cSld> <p:spTree> <p:pic
xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
Is there a way to turn this off?
notes: XMLStreamReader2 implements org.codehaus.stax2.typed.TypedXMLStreamReader and is actually XMLStreamReader.
parent.getWriter() also returns an XMLStreamReader2.
thanks - dave

AWS DynamoDB - converter class - "Bad request, unable to parse JSON"

I've made a generic method that is convertor class for complex classes and 2nd one for enums. I have Recipe class that is complex so I used #DynamoDBTypeConverted(converter = ObjectConverter.class)
This is my converter class:
public class ObjectConverter<T extends Object> implements DynamoDBTypeConverter<String, T> {
ObjectMapper objectMapper = new ObjectMapper();
#Override
public String convert(T object) {
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
throw new IllegalArgumentException("Unable to parse JSON");
}
#Override
public T unconvert(String object) {
try {
T unconvertedObject = objectMapper.readValue(object, new TypeReference<T>() {
});
return unconvertedObject;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
This is convertor class for enums:
public class EnumConverter<T extends Object> implements DynamoDBTypeConverter<String, List<T>> {
#Override
public String convert(List<T> objects) {
//Jackson object mapper
ObjectMapper objectMapper = new ObjectMapper();
try {
String objectsString = objectMapper.writeValueAsString(objects);
return objectsString;
} catch (JsonProcessingException e) {
//do something
}
return null;
}
#Override
public List<T> unconvert(String objectsString) {
ObjectMapper objectMapper = new ObjectMapper();
try {
List<T> objects = objectMapper.readValue(objectsString, new TypeReference<List<T>>() {
});
return objects;
} catch (JsonParseException e) {
//do something
} catch (JsonMappingException e) {
//do something
} catch (IOException e) {
//do something
}
return null;
}
The problem is when I try to test CRUDs methods.. I have addProduct method and this one works fine, I created addRecipe method and it looks almost the same, but here I have problem while posting in Postman i got an error: "Bad request, unable to parse JSON".
And information from log file:
"Can not deserialize instance of java.util.ArrayList out of START_OBJECT token at [Source: {"id":null,"name":"test","labels":["GLUTEN_FREE"],"author":{"name":"Plejer Annołn","id":"testID2"},"media":{"name":"heheszki","url":"http://blabla.pl","mediaType":"IMAGE"},"recipeElements":{"product":{"id":927c3ed3-400b-433d-9da0-1aa111dce584,"name":"bąkiKacpraNieŚmierdzą","calories":1000,"fat":400.0,"carbo":20.0,"protein":40.0,"productKinds":["MEAT"],"author":{"name":"Plejer Annołn","id":"testID2"},"media":{"name":"heheszki","url":"http://blabla.pl","mediaType":"IMAGE"},"approved":false},"weight":"100"},"approved":false}; line: 1, column: 190] (through reference chain: pl.javamill.model.kitchen.Recipe["recipeElements"])"
What can be wrong?
The methods in the converter class are always returning a value even if exceptions are thrown (unless they are RuntimeExceptions), though they may not be correctly marshaling/unmarshaling the Product in RecipeElement. A better alternative is to annotate the getRecipeElement() method in your class with #DynamoDBTypeConvertedJson, that provides out-of-the-box JSON marshaling/unmarshaling. It may be something to do with the HTTP request you are sending in Postman too. You should add more information on the getProduct(), setProduct() methods and the actual postman request (without any sensitive information).

Jackson Parsing with java

I really hate to do this, but I have two questions: can Jackson 2.7.3 parse the following url and can do I have to parse every part of the JSON?
Here is the code I am working with so far:
public class Song {
private String tracks;
private String album;
private String images;
public void setTracks(String tracks){
this.tracks=tracks;
}
public void setAlbum(String album){
this.album= album;
}
public void setImages (String images){
this.images= images;
}
}
And
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
ObjectMapper mapper = new ObjectMapper();
Document doc = Jsoup.connect("http://api.spotify.com/v1/search?q=track:" + finalSong + "%20artist:" + finalArtist+"%20" + "&type=track").ignoreContentType(true).get();
String title = String.valueOf(doc.body().text());
Song obj = mapper.readValue(String.valueOf(title), Song.class);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
thread.start();
return null;
}
All I need is the "preview_url" and one of the "images" url towards the top
the JSON is located at https://api.spotify.com/v1/search?q=track:Ready%20To%20Fall%20artist:rise%20against%20&type=track.
Do you necessary need to map your Json response into a class?
If not you can get your desired values as following e.g. for preview_url
You can use readTree to map the json result into a tree of nodes.
There after you can use findPath to search for the property you looking for.
In the case of image it contains an array. Thus if you want to select a specific item from that list you get use get to select the specific item you want.
example
JsonNode readTree = mapper.readTree(body);
for (JsonNode node : readTree.findPath("items")) {
System.out.println(node.findPath("images").get(2));
System.out.println(node.findPath("preview_url"));
}

Java validation of a URL through Regular Expression

Java validation of a URL through Regular Expression
String url = "https://my-company-08.vv.xyz.com/abc.svc/Abcdef(id='{0}',text='ABC.XYZ')?$query=xxxx&$format=xml";
URLs are potentially complex beasts with many possible variants. If you write your own regex parser you will most likely fail to cover all cases. Use the built in URI or URL class to do it for you...
private static boolean isValidUri(String candidate) {
try {
new URI(candidate);
return true;
} catch (URISyntaxException e) {
e.printStackTrace();
return false;
}
}
With URL
private static boolean isValidUrl(String candidate) {
try {
new URL(candidate);
return true;
} catch (MalformedURLException e) {
e.printStackTrace();
return false;
}
}
Your specific syntax errors....
// returns false, error at character 51 which is the first (
System.out.println(isValidUri("https://my-company-08.vv.xyz.com/abc.svc/Abcdef(id= '{sd54asds2f21sddf}',text='ABC.XYZ')?$query=myClient&$format=xml"));
// returns true without the (id= '{sd54asds2f21sddf}',text='ABC.XYZ') stuff
System.out.println(isValidUri("https://my-company-08.vv.xyz.com/abc.svc/Abcdef?$query=myClient&$format=xml"));

GSON password serialization policy

I want to create serialization policy, that would decode fields in objects which are passwords. If the field's name contains 'password' I would like GSON to use my defined encryption alghoritm. I tried to extend TypeAdapter and plug it to GsonBuilder, but then I loose all functionality from TreeTypeAdapter. Any ideas?
I have something like this but I need to do all the work from TreeTypeAdapter myself:
public class PasswordStringAdapter extends TypeAdapter<String> {
#Override
public void write(JsonWriter out, String value) throws IOException {
String keyName = getKeyName(out);
}
private String getKeyName(JsonWriter writer) {
try {
Field name = writer.getClass().getDeclaredField("deferredName");
name.setAccessible(true);
String fieldName = (String) name.get(writer);
//if field name contains password then encode it
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
It tured out that after decoding my password I just need to do:
out.value(value);
Please comment if you have better ideas how to do that.

Categories