Jackson treat field as object and include annotation in value - java

I have an interesting problem and not sure what the best way to design it. Would appreciate any inputs.
I have a bean class that needs to be converted to Json. The problem is that the field have custom property annotations.
#Descriptors(type="property", dbColumn="currency")
private String currency = USD; //(initializing for brevity)
I want Json that looks like this:
{
"currency": {
"type": "property",
"dbColumn": "currency",
"value": "USD"
}
}
Verbose way is to create a util triad and convert annotations into fields and then use that for json. Is there any other better way to achieve this.

Related

Rest Template binding with root array

I'm trying to use Rest Template to bind JSON to POJOs.
Imagine having a SpaceX class and a Rocket class, while the SpaceX class has a List<Rocket> attribute. I use the #JsonProperty annotation to let the Rest Template bind "Rocket ID" and "name" inside a Rocket object automatically.
My JSON file starts as array like following:
[
{
"Rocket ID": "1",
"name": "A"
},
{
"Rocket ID": "2",
"name": "B"
}
]
I'm able to consume the JSON file and fill a List<Rocket> manually like this:
public <T> List<T> createObjectsFromJSON(Class<T[]> responseType) {
ResponseEntity<T[]> responseEntity = restTemplate.exchange(URL, HttpMethod.GET, request, responseType);
T[] objects = responseEntity.getBody();
List<T> list = Arrays.asList(objects);
return list;
}
but I want to create a SpaceXobject and let the Rest Template fill in the List<Rocket> automatically.
I can't wrap my head around the answer on how to do it. I can't tell the Rest Template to bind the list via #JsonProperty, because there is no name.
If you can't change JSON structure than you have to write custom serialization and deserialization logic. You can use #JsonCreator and #JsonValue annotations:
The #JsonCreator annotation is used to tune the constructor/factory
used in deserialization. It’s very helpful when we need to deserialize
some JSON that doesn’t exactly match the target entity we need to get.
#JsonValue indicates a single method that should be used to serialize
the entire instance.
Or #JsonSerialize and #JsonDeserialize:
#JsonSerialize is used to indicate a custom serializer will be used to
marshall the entity.
#JsonDeserialize is used to indicate the use of a custom deserializer.
This article contains more details and examples: http://www.baeldung.com/jackson-annotations

Jackson Serializing Object as String

so I have an Item class which looks like this(extra stuff excluded):
{
"id": 1,
"item": "something",
"account": {
"id": 5,
"name": "somename"
}
}
I want the owner tap to appear for example like this
{
"id": 1,
"item": "something",
"account": "somename"
}
I know how to do this by changing the way Item is serialized in Jackson, however if I am to change the way I serialize Item, I will have to include all the extra fields it has, also Item is a base class so I have to do something with all the child classes as well, which is too much work (or is it, dunno if anyone has an easy solution how to serialize just one field and include all the rest). So my question is can I just serialize the Account class and make it return a simple String (not a json object or anything like that).
I've tried working around with the JsonGenerator to make it look similar but the best I've got to so far is:
{
"id": 1,
"item": "something",
"account": {"account":"somename"}
}
Thanks!
I think what you want is #JsonIdentityInfo from Jackson.
This annotation allows you to specify how a child entity is serialized in a parent entity.
Here is an example:
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="productDescription")
#JsonIdentityReference(alwaysAsId=true) // otherwise first ref as POJO, others as id
private Product product;
This tells Jackson that the product bean should be serialized using its "productDescription" field.
You can also check this tutorial:
http://www.baeldung.com/jackson-annotations
Scratch that, I've found my mistake was that I always started with:
jsonGenerator.writeStartObject();
and ended with:
jsonGenerator.writeEndObject();
which itself made it return an object. All I had to do is just use the writeString method.

Jackson CustomSerializer for specific fields

I have a requirement to take a document with ~60 fields and map it to a customer schema. Our schema has one field that I have as an array like so:
"documents": [{
"type": "Resume",
"url": "https://.s3.amazonaws.com/F58723BD-6148-E611-8110-000C29E6C08D.txt"
}, {
"type": "Reference",
"url": "https://.s3.amazonaws.com/F58723BD-6148-E611-8110-000C29E6C08D.txt"
}]
I need to transform that to:
"document1": {"type":"Resume", "https://.s3.amazonaws.com/F58723BD-6148-E611-8110-000C29E6C08D.txt"}
"document2": {"type":"Reference", "url":"https://.s3.amazonaws.com/F58723BD-6148-E611-8110-000C29E6C08D.txt"}
I've started a cumstom serializer but would really, really like to not have to write a custom serializer for all 60 fields to just do that one transform. Is there a way to tell jackson to serialize all other fields as normal and use my logic for just this one instance?
I have tried a number of options and keep getting the ever-so-helpful error:
com.fasterxml.jackson.core.JsonGenerationException: Can not write a field name, expecting a value
If I could even determine what this means it would be greatly helpful.
Thanks in advance!
A possible solution is to have the cumstom serializer call the default serializer for all those fields that can undergo default serialization.
See this thread for how to do it How to access default jackson serialization in a custom serializer
If you create, from the input, a map where the values are a string with raw Json, you can use the custom serializer written by Steve Kuo in Jackson #JsonRawValue for Map's value

Validation conventions in Java

I have an object. Let's call it `Customer' that is being serialized from a JSON object. Customer has many different fields, but for simplicity let's say that it has twenty (five of which are phone numbers). Is there any sort of convention for validating these fields? I've created one giant method that checks each individual field itself or by calling a method for certain length constraints, email downcasing and validation, phone numbers are stripped of all non-numeric values, length checked, validated, and so on.
All of these methods are held within the Customer class and it's starting to become a little sloppy for my liking. Should I create another class called CustomerValidators? Perhaps several other classes such as EmailValidator, PhoneValidator etc.? Is there any sort of convention here that I'm not aware of?
Try JSR-303 Bean validation. It lets you do things like:
public class Customer {
#Size(min=3, max=5) //standard annotation
private String name;
#PhoneNumber(format="mobile") //Custom validation that you can write
private String mobile;
#PhoneNumber(format="US Landline") //... and reuse, with customisation
private String landline
#Email //Or you can reuse libraries of annotations that others make, like this one from Hibernate Validator
private String emailAddress;
//... ignoring methods
}
The best documentation of this, in my opinion, is for the Hibernate Validator implementation of the spec.
Is your customer object use-case specific? I recommend exposing a use-case specific object for service invocations. The data from this object is then mapped onto your reusable, rich domain objects. (Eg using Dozer).
The reason we have use-case specific objects for service in/out payloads is the "don't spill your guts" principle (aka contract first) - this way you can evolve your application model without effecting service subscribers.
Now the validation:
You can use the annotation-based JSR-303 validation to verify that the input falls within acceptable ranges.
More complex rules are expressed with methods on the rich domain model. Avoid the anaemic domain classes anti-pattern - let them have rich, OO behaviors. To do this they may need to enlist collaborators. Use dependency injection to provide these. DI on non-container managed classes' eg persistent model instances can be achieved using Spring's #Configurable annotation (among other ways).
There is of course the Java EE validation API. How suitable it is for you depends on your environment.
As you already have a JSON structure filled with data that require validation you might have a look into JSON schema. Although it is still in draft it is not that complicated to learn.
A simple JSON schema might look like this:
{
"$schema": "http://json-schema.org/schema#",
"id": "http://your-server/path/to/schema#",
"title": "Name Of The JSON Schema",
"description": "Simple example of a JSON schema",
"definitions": {
"date-time": {
"type": "object",
"description": "Example of a date-time format like '2013-12-30T16:15:00.000'",
"properties": {
"type": "string",
"pattern": "^(2[0-9]{3})-(0[1-9]|1[012])-([123]0|[012][1-9]|31)[T| ]?([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(.[0-9]{1,3}[Z]?)?$"
}
}
},
"type": "object",
"properties": "{
"nameOfField": {
"type": "string"
},
"nameOfSomeIntegerArray": {
"type": "array",
"items": {
"type": "integer"
},
"minItems": 0,
"maxItems": 30,
"uniqueItems": true
},
"nameOfADateField": {
"$ref": "#/definitions/date-time"
}
},
"required": [ "nameOfRequiredField1", "nameOfRequiredField2" ],
"additionalProperties": false
}
The definitions part allows the definition of some element you can refer to using "$ref". The URI following "$ref" starts with a # which means it refers to the local schema; http://your-server/path/to/schema so to say. In the sample above it defines a date-time format which can be used to validate JSON fields a reference to the date-time definition has been set for. If the value inside the field does not match the regular expression validation will fail.
In Java a couple of libraries are available. I'm currently using json-schema-validator from Francis Galiegue. Validating a JSON object using this framework is quite simple:
public boolean validateJson(JsonObject json) throws Exception
{
// Convert the JsonObject (or String) to a internal node
final JsonNode instance = JsonLoader.fromString(json.toString());
// Load the JsonSchema
final JsonNode schema = JsonLoader.fromResource("fileNameOfYourJsonSchema");
// Create a validator which uses the latest JSON schema draft
final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
final JsonValidator validator = factory.getValidator();
// Validate the JSON object
final ProcessingReport report = validator.validate(schema, instance);
// optional error output
final Iterator<ProcessingMessage> iterator = report.iterator();
while( iterator.hasNext() )
{
final ProcessingMessage message = iterator.next();
System.out.println(message.getMessage());
// more verbose information are available via message.getJson()
}
return report.isSuccess();
}

Deserialize self referencing objects with Jackson

I have a JSON string looking like that (simplified):
[
{ "id":1, "friends":[2] },
{ "id":2, "friends":[1,3] },
{ "id":3, "friends":[] }
]
The content of friends are ids of other users in the list.
Is it possible somehow to create a Java class like the one below from the JSON just with Data Binding using Jackson or do I need an intermediate step for that?
public class User {
private long userid;
private List<User> friends;
// ... getters/setters
Thanks for your help.
There is no fully annotative way to do this, so you would need custom JsonSerializer / JsonDeserializer. Jackson 1.9 adds two new features that might help:
ValueInstantiators, so you can add constructors for deserializer to convert from basic integer into POJO
Value injection so you could pass additional context object (which you would need to find ids of already deserializer objects, to map then from integer to instance)
However I am not 100% sure how to combine these two features for specific use case...

Categories