Multiple aliases present in json during jackson deserialization - java

I have a "Request" POJO for my Java API service (Java 11). The POJO is created using Jackson deserialization (jackson databind 2.12.3). One of the POJO's fields has an alias (#JsonAlias) for backward compatibility in the API. How do I instruct jackson to throw an error if both versions of the field are present in the json (actual field name version & aliased version) ?
Here's a small demo app for the above scenario:
// Sample POJO
#lombok.Data
public class A {
#com.fasterxml.jackson.annotation.JsonAlias("y")
private int x; // Field names "x" with alias "y"
}
// Executed code
var om = new ObjectMapper().disable(MapperFeature.IGNORE_MERGE_FOR_UNMERGEABLE);
System.out.println(om.readValue("{\"x\": 1}", A.class));
System.out.println(om.readValue("{\"y\": 1}", A.class));
System.out.println(om.readValue("{\"x\": 1, \"y\": 1}", A.class));
System.out.println(om.readValue("{\"x\": 1, \"y\": 2}", A.class));
System.out.println(om.readValue("{\"y\": 1, \"x\": 2}", A.class));
// Output
A(x=1)
A(x=1)
A(x=1)
A(x=2)
A(x=2)
I need at least the last 2 cases to fail with a Jackson mapping related exception. The 3rd case may/may not fail (probably should fail, since the equals can get complex at times).
I tried checking if Jackson has anything that can be enabled/disabled in it's databind module's MapperFeatures but didn't have any luck.
I also tried checking in JsonParser.Feature & DeserializationFeature, but these deal more with parsing the actual Json input, rather than handling POJO / annotation processing, so I don't expect anything from in there...

This feature currently does not exist in Jackson.
Feature Request: https://github.com/FasterXML/jackson-databind/issues/3184

Related

How to add description attribute while generating JSON schema from POJOs using codehaus package classes

I intend to convert my POJOs to a JSON Schema.
In the existing POJOs we have annotations from the codehaus package:
#JsonProperty("address") where the corresponding import is:
import org.codehaus.jackson.annotate.JsonProperty;
I can't use codehaus api to generate the schema as we have a recursive JSON structure and I get StackOverflowError.
So, I tried using the fasterxml's jackson-module-jsonschema API to do this which works fine.
Sample output that I'm getting:
"Registration" : {
"type" : "object",
"id" : "urn:jsonschema:com:xyz.abc.Address",
}
I have two requirements:
Apart from "type" and "id", I also want to have a description attribute. I can add #JsonPropertyDescription attribute, which would work, but then each property will have one annotation from codehaus and another one from the fasterxml package. Is there an equivalent annotation in codehaus which can be used for this purpose?
Is there a way to have just the un-qualified class name in the "id" attribute (only "Address" i.e. without the qualified object path "xyz.abc.Address" and without "urn:jsonschema") ?
Code for schema generation using fasterxml:
ObjectMapper mapper = new ObjectMapper();
JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(mapper);
JsonSchema schema = schemaGen.generateSchema(DashboardDef.class);
String generatedJsonSchema = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema);
If it is possible just replace codehaus annotation by fasterxml one. codehaus is not supported anymore and should be avoided. For more info take a look at: org.codehaus.jackson versus com.fasterxml.jackson.core.
If you really want to dive into project with these two libraries you should take a look at AnnotationIntrospector class which allow extra configuration and linking many different libraries with Jackson framework. See similar question: How to make fasterxml ObjectMapper work with codehaus annotations.
To manipulate JSON Schema you can implement your own SchemaFactoryWrapper. See also:
Removing “id” from JSON schema when creating it from POJO using jackson.
Generating flat JSON schema with all $ref resolved from Java class #132
PS: I know this is not ideal answer (it does not contain direct solution) but I wanted point you some topics which you should start from to solve your problems, and comments are too small for this.

Response does not contain zero integers

I have restful API and use Jetty as a server. I send a post request to create my object which contains some skill list. Skill contains of String id and Integer value fields. When I use 0 or "0" for my Integer field with the get response I get the skill array without value field at all.
#XmlRootElement
#JsonAutoDetect(isGetterVisibility = Visibility.NONE, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE,
creatorVisibility = Visibility.NONE, fieldVisibility = Visibility.NONE)
public class Skill
{
#com.fasterxml.jackson.annotation.JsonProperty(value="id")
#javax.validation.constraints.NotNull
private java.lang.String _id;
#com.fasterxml.jackson.annotation.JsonProperty(value="value")
#javax.validation.constraints.NotNull
private java.lang.Integer _value;
// getters and setters
}
My request body is like this:
{
// some other fields
"skills": [{
"id":"Swedish",
"value":0
},{
"id":"Finnish",
"value":"0"
}]
}
After applying necessary changes to my object I pass it to be returned via this line:
Response.ok().entity(myObject).build();
The body of the get response is like this:
{
// some other fields
"skills" : [ {
"id" : "Finnish"
}, {
"id" : "Swedish"
} ]
}
With other values everything works fine, however, 0 seems to be so special that it doesn't even include this field to the object.
The question is Why and How can I solve it?
The problem is not in Jetty, Jersey or YaaS. The problem seems to be in Jackson. Jackson does the serialization/deserialization and seems to have some optimization, thus zeros are skipped.
Unfortunately I haven't found any resource yet which says exactly why would you skip 0 and I didn't manage to find the place in Jackson code where this happens.
Possible solutions:
Use annotation #JsonInclude(JsonInclude.Include.ALWAYS) for your field and it will not be skipped.
Don't allow zeros for your Integer field.
Use String type instead of Integer.
The problem is that my object is generated by YaaS, thus, I cannot just change by generated object and not sure if YaaS has the possibility to generate the object with the annotation from the 1 item. I assume that in this case the 2 option might be the best.
The problem is in version of Jackson library.
When we add JsonFeature by default we have serializeJsonEmptyValues=false.
In this case in the method JsonFeature#initDefaultObjectMapper we will come to the point where we do objMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
If we have a look to the javaDoc of NON_EMPTY field, we will see the following:
Compatibility note: Jackson 2.6 included a wider range of "empty"
values than either earlier (up to 2.5) or later (2.7 and beyond)
types; specifically: Default values of primitive types (like 0 for
int/java.lang.Integer and false for bool/Boolean) Timestamp 0 for
date/time types With 2.7, definition has been tightened back to only
containing types explained above (null, absent, empty String, empty
containers), and now extended definition may be specified using
NON_DEFAULT.
So, which means that if you use the version 2.6 the zeros will disappear. And this happens to be in our project because we use Redisson which uses the version 2.6. of Jackson library.
you have different value types for similar keys:
int 0 for "value" of "Swedish" and String "0" for "value" of "Finnish".
This may cause problem if some kind of object by fields building is involved.
I had the same problem but I didn't use #javax.validation.constraints.NotNull.
What I had was
ObjectMapper objectMapper = new org.codehaus.jackson.map.ObjectMapper();
objectMapper.setSerializationInclusion(Include.NON_EMPTY);
MyClass myClass = new MyClass();
myClass.setStringField("some value");
myClass.setIntField(0);
String json = objectMapper.writeValueAsString(myClass);
System.out.println(json); // --> { "stringField" : "some value" }
It didn't print the intField with value zero. All I had to change was the NON_EMPTY rule to this:
objectMapper.setSerializationInclusion(Include.NON_ABSENT);
String json = objectMapper.writeValueAsString(myClass);
System.out.println(json); // --> { "stringField" : "some value" }

Check if JSON is valid in JAVA using Jackson

I have a JSON string which I am storing it in DB as a string. In front-end, I am rendering this JSON as object.
I am using:
JSON.parse(string);
Uncaught Syntax error: Unexpected Token
String :
{
"id": "295cd59f-4033-438c-9bf4-c571829f134e",
"from": "Shrisha S.<shrisha#s.com>",
"to": [
"Katie Porter <katie.porter#ss.com>"
],
"cc": [
"Jack d<jack.d#dd.com>, Keerthi<keerthi.s#dd.com>"
],
"bcc": [
]
}
Is there any way I can check If JSON is valid or not in JAVA?
One thing to be noted here is that, I don't have a schema defined for JSON which I can map to, i.e. JSON can hold anything.
I am currently trying out with JACKSON but for that I need a pre-defined schema which I don't have. Is there anyway this can be fixed?
You can read it as a JsonNode, no need to map it to a specific Class, its generic:
try{
ObjectMapper objectMapper = ...;
JsonNode jsonNode = objectMapper.readTree(yourJsonString);
} catch(JsonProcessingException e){........}
There are two different parts to the question. First is whether it is valid JSON, and second whether it contains specific set of information.
#pdem already answered first part (you can also read JSON as java.lang.Object to get the same effect).
But for second part, JSON Schema is not usually a good way, as it focuses on JSON aspects but not on more meaningful part of actual data, possible sub-typing and so on, which matter at Java level where all actual data processing occurs.
So usually you would define a POJO (or ideally just use one you use for actual data processing), bind to it (with ObjectMapper.readValue()), and then check whether data is not only technically valid wrt low-level data types, but also that it conforms to additional business constraints.
For latter part you can either write Java code, or use an annotation based framework such as Bean Validation API (JSR-303); see for example:
http://beanvalidation.org/
plus there are many #bean-validation tagged questions here as well related to usage. Some frameworks add explicit support for it; for example the best Java service framework, DropWizard does this. Others like Spring Boot have support as well.
JSON specification forbids it from using newline characters, make sure you are replacing newline characters see
Regex replace all newline characters with comma
make sure you do this before storing it in DB.
public boolean isValidJson(final String json) {
try {
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonNode = objectMapper.readTree(json);
return jsonNode instanceof ContainerNode;
} catch (JsonProcessingException jpe) {
return false;
}
}

Deserialize json to java using jackson - issues with special characters

I am using jackson (jersey and jetty) for my REST webservices - and all is going well. But I have a requirement to include a special character in one of the name value pairs in json post request. i.e.
json request (in post body)-
{
"id": "1",
"print-color" : "red"
}
//"-" in "print-color" is giving problems.
Now inside my corresponding java bean for this object Item.java class, I cant make a property with name print-color (because "-" is not allowed). How do I deal with it in mapping?
Thanks.
You could try following in Java POJO:
#JsonProperty("print-color")

Jackson annotations broken in Scala from 1.9 to 2.1

Just upgraded Jackson from 1.9 to 2.1 and immediately noticed that #(JsonProperty#field) annotations are broken. Note the special #field for Scala case classes. Here's a sample:
case class Watcher(
#(JsonProperty#field)("guid")
#(RiakKey#field)
val guid: String,
#(JsonProperty#field)("socialNetwork")
val socialNetwork: String, // instragram, twitter
)
When I go to pull a Watcher serialized as JSON from the database, Jackson goes to deserialize it and it throws the exception:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "guid" (class com.domain.SocialStreamService.models.Watcher), not marked as ignorable (0 known properties: ])
Now since this was working in 1.9, I am assuming something has changed. Anyone know the cause of the issue? Thanks!
It was caused by a namespace issue and the fact that I was using Jerkson (which still pulled in 1.x as a dependency, thus not throwing compiler errors). To solve the issue, I had to go change the namespaces from com.codehaus to com.fasterxml.
In the meantime, there is a legacy introspector for those who need it: https://github.com/Laures/jackson-legacy-introspector

Categories

Resources