Is there a way to serialize this class? - java

#JsonSerialize(using = TestDefSerializer.class)
public class TestDef{
private List<TestStep> steps = new LinkedList<>();
private String name;
} //Getter and Setters are defined
I can't seem to figure out a way after this
public class TestDefSerializer extends StdSerializer<TestDef> {
public TestDefSerializer(Class<TestDef> t) {
super(t);
}
public TestDefSerializer(){
this(TestDef.class);
}
#Override
public void serialize(TestDef testDefinition, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
// What should go here in order to serialize List<TestStep> ???
}
}
TestStep has a couple of fields namely responseDef (which has path , method) , requestDef (mathcing , status) etc. I wish to skip a couple of fields in responseDef and requestDef

There are chances you don't even need to implement a
TestDefSerializer at all , because Jackson is probably
smart enough to pick up enough information from the getters
of your TestDef class.
Just omit the line
#JsonSerialize(using = TestDefSerializer.class)
on your TestDef class and check if this will already
produce the JSON output you want.
But anyway, here is how to proceed if you want to
implement your own TestDefSerializer.
Look up the the API docu of JsonGenerator.
It describes all the write... methods available
for writing the JSON pieces.
For example, there is method writeStartArray() for writing a [,
and writeEndArray() for writing a ].
So in your TestDefSerializer class you may end up
with a serialize method looking like this:
#Override
public void serialize(TestDef testDefinition, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject(); // write {
jsonGenerator.writeFieldName("name"); // write "name":
jsonGenerator.writeString(testDefinition.getName());
jsonGenerator.writeFieldName("steps"); // write "steps":
jsonGenerator.writeStartArray(); // write [
for (TestStep testStep : testDefinition.getSteps()) {
jsonGenerator.writeObject(testStep); // this will invoke the serializer for TestStep
}
jsonGenerator.writeEndArray(); // write ]
jsonGenerator.writeEndObject(); // write }
}

Related

Jackson JsonInclude.Include.NON_NULL is not working with custom serialiser

I have a custom serialiser which extends JsonSerializer<T>
and in the ObjectMapper I have included setSerializationInclusion(JsonInclude.Include.NON_NULL).
I still see null field in response.
Currently, I ignore them by checking null for each property. I have almost 15 objects and it's very difficult to add null checking to each property. Object I am using is shared by my applications, that is the reason why I am using custom serialiser to name the properties
#Override
public void serialize(Person personBean, JsonGenerator jgen, SerializerProvider provider) throws IOException {
if(personBean.getFirstName() != null){
jgen.writeStringField("firstname", personBean.getFirstName() );
}
//etc...
}
How to avoid null check for each property and implement some generic code to avoid null values in my serialised response.
Unfortunately, when we write custom serialiser we need to take care about null values by ourself. To make it at least a little bit better we can add new writeStringField method and use it. For example:
class PersonJsonSerializer extends JsonSerializer<Person> {
#Override
public void serialize(Person value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartObject();
writeStringField(gen, "firstname", value.getFirstName());
gen.writeEndObject();
}
private void writeStringField(JsonGenerator gen, String fieldName, String value) throws IOException {
if (value != null) {
gen.writeStringField(fieldName, value);
}
}
}
If you need to change only property names you can use PropertyNamingStrategy option. There is a few possibilities like:
LOWER_CASE - Naming convention in which all words of the logical name are in lower case, and no separator is used between words.
KEBAB_CASE - Naming convention used in languages like Lisp, where words are in lower-case letters, separated by hyphens.
For more check documentation
Example ObjectMapper customisation could look like:
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CASE);
If there is no predefined strategy which satisfies your need you can use JsonView annotation.

Can JSONObject hold large formatted Double value using java?

Greetings,
I have JSONObject that contain payment information, today our customer asked for 10 digit number formatted as (1234567890.12), i have parameter total_amount , when i set this parameter value {"total_amount":123456789.23} it shown in server like {"total_amount":1.2345678923E8} , is there anyway that i can make JSONObject hold it as 123456789.23
You can have a deserialiser and utilise a fasterxml(com.fasterxml.jackson.databind.annotation.JsonSerialize) annotation
deserialiser class:
class DecimalJsonSerializer extends JsonSerializer<Double> {
#Override
public void serialize(Double value, JsonGenerator jsonGenerator, SerializerProvider provider)
throws IOException {
jsonGenerator.writeNumber(String.format("%.1f", value));
}
}
And the annotation on your field should look like:
#JsonSerialize(using = DecimalJsonSerializer.class)
private Double total_amount;

How inline object via jackson JsonGenerator?

Consider example:
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import java.io.File;
import java.io.FileInputStream;
public class Exmaple {
public static void main (String[] args) throws Exception {
Object object = new Object() {
private String id = "someId";
};
final JsonGenerator generator = new JsonFactory().createGenerator(System.out);
generator.writeStartObject();
generator.writeFieldName("data");
generator.writeBinary(new FileInputStream(new File("D:\\!Temp\\elasticsearch\\pdf.pdf")), -1);
generator.writeEndObject();
generator.writeObject(object);
generator.close();
}
}
The goal is to add all fields from object during json streaming. With that code I got:
{
"data": "JVBERi0xLjMKJ="
} {
"id": "someId",
}
How tell jackson to not write {} from object?
UPDATED
The exprected result is (e.g. data + all keys from java object):
{
"data": "JVBERi0xLjMKJ=",
"id": "someId",
}
Just don't call writeEndObject() after you call writeBinary It should look like:
final JsonGenerator generator = new JsonFactory().createGenerator(System.out);
generator.writeStartObject();
generator.writeFieldName("data");
generator.writeBinary(new FileInputStream(new File("D:\\!Temp\\elasticsearch\\pdf.pdf")), -1);
generator.writeObject(object);
generator.writeEndObject();
generator.close();
The JsonSerializer type has an unwrappingSerializer method that "unwraps" the serializer. For the BeanSerialier (which is the serializer used for writing objects), the returned serializer will simply not write the start and end of the object.
The provided example, rewritten to use this, looks like this:
final SerializerProvider serializerProvider = /* obtain serializer provider */;
final JsonSerializer<Object> objectSerializer = serializerProvider.findValueSerializer(object.getClass());
final JsonSerializer<Object> unwrappingSerializer = objectSerializer.unwrappingSerializer(NameTransformer.NOP);
final JsonGenerator generator = new JsonFactory().createGenerator(System.out);
generator.writeStartObject();
generator.writeFieldName("data");
generator.writeBinary(new FileInputStream(new File("D:\\!Temp\\elasticsearch\\pdf.pdf")), -1);
unwrappingSerializer.serialize(object, generator, serializerProvider);
generator.close();
Obtaining the SerializerProvider depends on the actual implementation, as the provided example does not use an ObjectCodec. Optimally, this code would live inside the serialize method of a custom serializer, where the SerializerProvider is given as an argument.
The NameTransformer passed to unwrappingSerializer can be used to easily map the names, for example by prefixing them. Using NameTransformer.NOP just writes the names as they are written by the original serializer.
You basically want to merge object variable into the generator's target object. If you can access object variable and you know its properties than you can simply use generator's methods to write them, e.g.:
generator.writeStringField("id", object.id)
Some properties might be complex objects (aka POJO) where you'll have to use writePOJOField(String fieldName, Object pojo); for writePOJOField to work you'll have to properly instantiate your JsonFactory, e.g. new JsonFactory(new ObjectMapper()). See also https://stackoverflow.com/a/73702885/4681265.
The other more generic approach is to generate the object JSON and then write it into generator's output using:
// see http://fasterxml.github.io/jackson-core/javadoc/2.13/
generator.writeRaw(char[] text, int offset, int len)
by skipping the object JSON's opening and enclosing braces.

How to get Jackson to use its JsonSerializable Interface?

Jackson docs say that a class that implements their JsonSerializable interface will be serialized by calling the Interface's serialize() method.
I tried this in a project that uses Jackson 2.8.4 under Jersey 2.25.
It continues to use Jackson's BeanSerializer to do default serialization based on public getters, instead of using the SerializableSerializer and the serialize() method.
Code looks like this fairly minimal example...
public class Minimal extends JsonSerializable.Base {
private String title;
private ZonedDateTime theTime;
public String getTitle() { return title; }
void setTitle(String title) { this.title = title; }
public ZonedDateTime getTheTime() { return theTime; }
void setTheTime(ZonedDateTime theTime) { this.theTime = theTime; }
#Override
public void serialize(JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
gen.writeFieldName("title");
gen.writeString(this.title);
// Other serialization...
gen.writeEndObject();
}
#Override
public void serializeWithType(JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException {
throw new UnsupportedOperationException("Not supported.");
}
}
I also tried other ideas to get it using the right serializer...maybe foolish ideas like...
public class Minimal implements JsonSerializable {
and
#JsonSerialize(using = SerializableSerializer.class)
public class Minimal extends JsonSerializable.Base {
and
#JsonSerialize(as = JsonSerializable.Base.class)
public class Minimal extends JsonSerializable.Base {
What am I missing to get this Jackson feature working?
I verified in Jackson's latest source code that the feature still exists. I suppose I can trace it through the 2.8.4 source in the debugger, but maybe someone knows the answer.
Apparently the answer to
"What am I missing?"
is Nothing.
After writing the question, I rebuilt everything again, restarted Tomcat, and redeployed and tested again and got my expected output.
So I will chalk this up to bad build, bad deploy, confused Classloader, something like that. I am leaving the question, since it provides an example that might help someone.

Jackson - converting java object to json - Need all key keys to upper case

Need your help on conversion of java objects to json.
current the json result showing all the key in small letter case, i need it to be upper case.
ObjectMapper mapper = new ObjectMapper();
Writer strWriter = new StringWriter();
mapper.writeValue(strWriter, obj);
String jsonString= strWriter.toString();
and the result is
[{"flags":"1","name":"Peter","location":"London","startDate":"2012-01-06 00:00"}]
but i want results like this (all key key value should be in UPPER CASE):
[{"FLAGS":"YU","NAME":"Peter","LOCATION":"London","STARTDATE":"2012-01-06 00:00"}]
and also is it possible to get like this also (key first letter in upper case):
[{"Flags":"1","Name":"Peter","Location":"London","StartDate":"2012-01-06 00:00"}]
Can anyone help me on this.
Thanks in advance.
There are multiple ways to do it with Jackson.
Annotations
You could annotate your object with #JsonProperty annotations on your fields or on your getter methods.
Example:
#JsonProperty("Name")
public final String name;
#JsonProperty("Location")
public String getLocation() {
return location;
}
Implement JsonSerializableWithType interface
#Override
public void serialize(final JsonGenerator jG, final SerializerProvider p)
throws IOException, JsonProcessingException
{
serializeWithType(jG, p, null);
}
#Override
public void serializeWithType(final JsonGenerator jG, final SerializerProvider p, final TypeSerializer typeSer)
throws IOException, JsonProcessingException
{
// here you can do your own serialization
}
I would advice to use the #JsonNaming annotation on class level.
Yet afaik there is no strategy out there to fit your needs for total uppercase. But you can probably just write your own.
In my case I needed first character uppercase. So I used the existing
#JsonNaming(value = UpperCamelCaseStrategy.class).

Categories