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.
Related
I'm using the com.fasterxml.jackson.databind.ObjectMapper in jackson-databind 2.11.2 and trying to serialize Java properties with null-value to something like this:
{ %Key% : "" }
I've tried:
ObjectMapper MAPPER = new JodaMapper();
DefaultSerializerProvider defaultSerializerProvider = new DefaultSerializerProvider.Impl();
defaultSerializerProvider.setNullValueSerializer(new JsonSerializer<Object>() {
#Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString("bla");
}
});
MAPPER.setSerializerProvider(defaultSerializerProvider);
But the NullValueSerializers serialize-method does not get triggered for any fields.
Has anybody some ideas?
I found the solution.... I had
#JsonInclude(JsonInclude.Include.NON_NULL)
at class level in the class that I wanted to serialize. When I remove the annotation I the code above works.
There are a couple of ways to achieve custom null value serialising:
If you want to serialise a null as an empty String, try using this annotation on a property, or setter:
#JsonSetter(nulls=Nulls.AS_EMPTY)
or the same for specific mapper:
MAPPER.configOverride(String.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
You can initialise properties with default values on the declaration or in the getter.
As you've already mentioned, by providing a custom serialiser.
I did try your code, and that serialised null value as expected when using an ObjectMapper instead of JodaMapper. Is there any particular reason for using a JodaMapper?
#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 }
}
I am developing a Spring boot application which uses Jackson annotations.
I want to read value of #JsonProperty from a config, instead of using constant string.
Example JSON input
{"s":12}
Code
I want to read property from my config:
#JsonProperty("${myconfig.fieldAlias.stream}")
private Integer stream;
instead of
#JsonProperty("s")
private Integer stream;
Issue
While executing the code above using config:
variable "s" is not identified as stream
unless I use constant #JsonProperty("s"), which is not desired.
Is it possible to use dynamic JsonProperty values? If so, what is the proper way to do so?
The name given to #JsonProperty must be statically given. What you can do is to overwrite the given name dynamically, by implementing a custom serializer for the propery:
public static class StreamSerializer extends JsonSerializer<Integer> {
#Override public void serialize(Integer value, JsonGenerator jsonGenerator, SerializerProvider provider)
throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("s", your_dynamic_name_here);// dynamic field name
jsonGenerator.writeEndObject();
}
}
and use it like this:
#JsonProperty("s")
#JsonSerialize(using = StreamSerializer.class)
private Integer stream;
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.
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).