How to exclude empty objects from Jackson ObjectMapper? - java

Basically I do not want any empty JSON arrays or objects to show up in my generated JSON files. I have already configured my ObjectMapper accordingly using the following method:
objectMapper.setSerializationInclusion(Include.NON_EMPTY);
This works fine for arrays, collections and Strings.
However if i have an empty object (= all properties are null or empty) it will still show up in the generated JSON like this:
"MyObject":{}
Here is a possible example of what I mean with an empty object:
class MyClass
{
String property1 = "";
Object property2 = null;
}
In this case I want the object to be excluded completely from the generated JSON file.
Is this possible? If yes, how to I have to configure my ObjectMapper in order to get the desired behavior?

To ignore the empty values such as you may have initialized the arrayList but there are no elements in that list. In that time using NOT_EMPTY annotation to ignore those empty value fields
#JsonInclude(Include.NON_EMPTY)
class Foo
{
String bar;
}

It's been a few years since the question was asked, but I hit this page looking for a solution. So here it is.
You need to annotate your class with NON_DEFAULT:
#JsonInclude(NON_DEFAULT)
class MyClass
{
String property1 = "";
Object property2 = null;
}
Global config is not enough as explicitly stated in the documentation:
http://fasterxml.github.io/jackson-annotations/javadoc/2.7/com/fasterxml/jackson/annotation/JsonInclude.Include.html#NON_DEFAULT
The new NON_DEFAULT is available since 2.7

Related

Can I ignore a getter-based write-only property during deserialization in Java Jackson?

I have a legacy JSON API class that I'm evolving to remove a certain property. It's currently at a point where the property value is always the same constant, so I would like my Java code to be just a simple getter with no underlying field for it. I want to continue serializing the value until I know that all my clients have migrated off of using the value. The object is only read by my clients, so I don't have to worry about them sending other values across.
public class MyType {
private String value;
public boolean isLegacyValue() {
return true;
}
}
That said, I don't want any test code or the like to fail if I deserialize a full value with the now-constant property. Is there a way I can tell Jackson to serialize a setter method-only property, but ignore it on deserialization? I tried a few different things, but I get a UnrecognizedPropertyException on deserialization. I'd rather not change the global DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES just for this one property.
{"value": "ABC", "legacyValue": true}
Also acceptable would be a way to tell Jackson to include the value without including a Java field for it.
I'm aware I can add a getter in addition to my setter, or make it a field, but both those options feel like they're confusing the Java API, as it's not actually matching the constant constraint:
public void setLegacyValue(boolean legacyValue) {
// No-op; only exists for Jackson deserialization
}
One thing I've found to work through trial and error is making it a final field. For whatever reason, Jackson knows to handle that as a write-only constant in a way that doesn't work with the getter without matching setter. This will be my solution if there's no way to do it with just a getter.
private final boolean legacyValue = true;
public boolean isLegacyValue() {
return legacyValue;
}
Jackson supports "one-way" properties using the access parameter of #JsonProperty. Annotate your property like this:
#JsonProperty(access = READ_ONLY)
public boolean isLegacyValue() {
return true;
}

How to make XStream map unmapped tags to an HashMap when parsing XML?

Have an XML document that I want to convert to a Java bean. I want to tag the missing fields in my bean to a hashMap because these field name keeps varying. Is there a way to do this?
For example, my XML looks like
<employee>
<firstname>stack</firstname>
<lastname>alpha</lastname>
<phone1>999-999-9999</phone1>
</employee>
My java bean look like
#XstreamAlias("employee")
public class Employee {
private String firstname;
private String lastname;
private map<String, String> unknownfields;
}
When I load the XML to my java bean, it should look like
firstname="stack", lastname="alpha", unknownfields=[{"phone1","999-999-9999"}]
Know this is a bad design, but wanted to check whether this could be implemented using xstream.
Implement your own Converter. Take a look at JavaBeanConverter for reference implementation because you want to be as close to that a possible.
The only place you would need to handle things differently is this (within the unmarshal method)
if (propertyExistsInClass) {
Class<?> type = determineType(reader, result, propertyName);
Object value = context.convertAnother(result, type);
beanProvider.writeProperty(result, propertyName, value);
seenProperties.add(new FastField(resultType, propertyName));
} else {
throw new MissingFieldException(resultType.getName(), propertyName);
}
Where, from the else block, it throws the MissingFieldException, you should populate your Map. The XML element name is easily available here, but you need to tweak for the value. The clue to get the value is in the if block just above:
Object value = context.convertAnother(result, type);
The only problem is you dont have a Java type to convert the value into. String maybe?
I would inherit JavaBeanConverter and just override the unmarshal method, but suit your needs.

How to tell Jackson to ignore a field during serialization if its value is null?

How can Jackson be configured to ignore a field value during serialization if that field's value is null.
For example:
public class SomeClass {
// what jackson annotation causes jackson to skip over this value if it is null but will
// serialize it otherwise
private String someValue;
}
To suppress serializing properties with null values using Jackson >2.0, you can configure the ObjectMapper directly, or make use of the #JsonInclude annotation:
mapper.setSerializationInclusion(Include.NON_NULL);
or:
#JsonInclude(Include.NON_NULL)
class Foo
{
String bar;
}
Alternatively, you could use #JsonInclude in a getter so that the attribute would be shown if the value is not null.
A more complete example is available in my answer to How to prevent null values inside a Map and null fields inside a bean from getting serialized through Jackson.
Just to expand on the other answers - if you need to control the omission of null values on a per-field basis, annotate the field in question (or alternatively annotate the field's 'getter').
example - here only fieldOne will be omitted from the JSON if it is null. fieldTwo will always be included in the JSON regardless of if it is null.
public class Foo {
#JsonInclude(JsonInclude.Include.NON_NULL)
private String fieldOne;
private String fieldTwo;
}
To omit all null values in the class as a default, annotate the class. Per-field/getter annotations can still be used to override this default if necessary.
example - here fieldOne and fieldTwo will be omitted from the JSON if they are null, respectively, because this is the default set by the class annotation. fieldThree however will override the default and will always be included, because of the annotation on the field.
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Foo {
private String fieldOne;
private String fieldTwo;
#JsonInclude(JsonInclude.Include.ALWAYS)
private String fieldThree;
}
UPDATE
The above is for Jackson 2. For earlier versions of Jackson you need to use:
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
instead of
#JsonInclude(JsonInclude.Include.NON_NULL)
If this update is useful, please upvote ZiglioUK's answer below, it pointed out the newer Jackson 2 annotation long before I updated my answer to use it!
With Jackson > 1.9.11 and < 2.x use #JsonSerialize annotation to do that:
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
In Jackson 2.x, use:
#JsonInclude(JsonInclude.Include.NON_NULL)
You can use the following mapper configuration:
mapper.getSerializationConfig().setSerializationInclusion(Inclusion.NON_NULL);
Since 2.5 you can user:
mapper.setSerializationInclusion(Include.NON_NULL);
You can set application.properties:
spring.jackson.default-property-inclusion=non_null
or application.yaml:
spring:
jackson:
default-property-inclusion: non_null
http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
in my case
#JsonInclude(Include.NON_EMPTY)
made it work.
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonInclude(JsonInclude.Include.NON_EMPTY)
should work.
Include.NON_EMPTY indicates that property is serialized if its value is not null and not empty.
Include.NON_NULL indicates that property is serialized if its value is not null.
This Will work in Spring boot 2.0.3+ and Jackson 2.0+
import com.fasterxml.jackson.annotation.JsonInclude;
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ApiDTO
{
// your class variable and
// methods
}
If you want to add this rule to all models in Jackson 2.6+ use:
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
If in Spring Boot, you can customize the jackson ObjectMapper directly through property files.
Example application.yml:
spring:
jackson:
default-property-inclusion: non_null # only include props if non-null
Possible values are:
always|non_null|non_absent|non_default|non_empty
More: https://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html#howto-customize-the-jackson-objectmapper
For Jackson 2.5 use :
#JsonInclude(content=Include.NON_NULL)
If you're trying to serialize a list of object and one of them is null you'll end up including the null item in the JSON even with
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
will result in:
[{myObject},null]
to get this:
[{myObject}]
one can do something like:
mapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
#Override
public void serialize(Object obj, JsonGenerator jsonGen, SerializerProvider unused)
throws IOException
{
//IGNORES NULL VALUES!
}
});
TIP: If you're using DropWizard you can retrieve the ObjectMapper being used by Jersey using environment.getObjectMapper()
This has been troubling me for quite some time and I finally found the issue. The issue was due to a wrong import. Earlier I had been using
com.fasterxml.jackson.databind.annotation.JsonSerialize
Which had been deprecated. Just replace the import by
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
and use it as
#JsonSerialize(include=Inclusion.NON_NULL)
Global configuration if you use Spring
#Configuration
public class JsonConfigurations {
#Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
builder.serializationInclusion(JsonInclude.Include.NON_EMPTY);
builder.failOnUnknownProperties(false);
return builder;
}
}
We have lot of answers to this question. This answer may be helpful in some scenarios
If you want to ignore the null values you can use the NOT_NULL in class level.
as below
#JsonInclude(Include.NON_NULL)
class Foo
{
String bar;
}
Some times you may need to ignore the empty values such as you may have initialized the arrayList but there is no elements in that list.In that time using NOT_EMPTY annotation to ignore those empty value fields
#JsonInclude(Include.NON_EMPTY)
class Foo
{
String bar;
}
Case one
#JsonInclude(JsonInclude.Include.NON_NULL)
private String someString;
Case two
#JsonInclude(JsonInclude.Include.NON_EMPTY)
private String someString;
If someString is null, it will be ignored on both of cases.
If someString is "" it just only be ignored on case two.
The same for List = null or List.size() = 0
Try this -
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public class XYZ {
protected String field1;
protected String field2;
}
And for non-null values (On getters/class level) -
#JsonSerialize(include=JsonSerialize.Inclusion.NON_EMPTY)
Jackson 2.x+ use
mapper.getSerializationConfig().withSerializationInclusion(JsonInclude.Include.NON_NULL);
Also, you have to change your approach when using Map myVariable as described in the documentation to eleminate nulls:
From documentation:
com.fasterxml.jackson.annotation.JsonInclude
#JacksonAnnotation
#Target(value={ANNOTATION_TYPE, FIELD, METHOD, PARAMETER, TYPE})
#Retention(value=RUNTIME)
Annotation used to indicate when value of the annotated property (when used for a field, method or constructor parameter), or all properties of the annotated class, is to be serialized. Without annotation property values are always included, but by using this annotation one can specify simple exclusion rules to reduce amount of properties to write out.
*Note that the main inclusion criteria (one annotated with value) is checked on Java object level, for the annotated type, and NOT on JSON output -- so even with Include.NON_NULL it is possible that JSON null values are output, if object reference in question is not `null`. An example is java.util.concurrent.atomic.AtomicReference instance constructed to reference null value: such a value would be serialized as JSON null, and not filtered out.
To base inclusion on value of contained value(s), you will typically also need to specify content() annotation; for example, specifying only value as Include.NON_EMPTY for a {link java.util.Map} would exclude Maps with no values, but would include Maps with `null` values. To exclude Map with only `null` value, you would use both annotations like so:
public class Bean {
#JsonInclude(value=Include.NON_EMPTY, content=Include.NON_NULL)
public Map<String,String> entries;
}
Similarly you could Maps that only contain "empty" elements, or "non-default" values (see Include.NON_EMPTY and Include.NON_DEFAULT for more details).
In addition to `Map`s, `content` concept is also supported for referential types (like java.util.concurrent.atomic.AtomicReference). Note that `content` is NOT currently (as of Jackson 2.9) supported for arrays or java.util.Collections, but supported may be added in future versions.
Since:
2.0

Dynamically entering class literal as method argument at runtime

I have an application which makes use of an external library (Jackson), and the method I need requires a class literal as an argument. So if I wish to parse my JSON string into a User object:
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(new File("user.json"), User.class);
Now, I wish to use this method dynamically (i.e. parse different JSON strings using the same line of code). For example:
String json1 = "{"type":"jacket",...}";
String json2 = "{"type":"sweater",...}";
Object object = mapper.readValue(json1/json2, ???);
//returns a Jacket object OR Sweater object based on the "type" key
//i.e. use Jacket.class as the 2nd argument if "type" is "jacket"
//OR Sweater.class if "type" is "sweater"
//After getting the deserialized object,
//if object is Jacket, cast as a Jacket
//if object is Sweater, cast as a Sweater
Of course, the JSON string in question can be for any class, so I can't simply hard-code an if-else loop. I've looked at custom serializers, but frankly am quite lost at what it's talking about, and would like some help in how I can go about this.
In summary, I need some way to first define a class literal from a String, and then cast the resulting Object into the specific class (but my focus is on getting readValue to work dynamically).
Looks like you need a mapping somewhere between JSON type variable and Java class type.
Generally result should be something like this map:
Map<String, Class<? extends YourSupertype>> map = new HashMap<>();
map.put("sweater", Sweater.class);
map.put("jacket", Jacket.class);
Just store possible clothing types somewhere in a file, then do something like:
String clothingType = nextEntryFromFile();
String className = constructClassNameFromClothingType(clothingType);
map.put(clothingType, Class.forName(className));
Since version 1.5 Jackson supports Polymorphic Type Handling, check here http://www.cowtowncoder.com/blog/archives/2010/03/entry_372.html
there are examples on how to correctly handle deserialization in those cases.

How to make Jersey/Jackson serialize empty list; single element list as an array

Using Jersey and Jackson to create a REST interface, how do I get List fields to be serialized as a list when there are 0 or 1 elements in them. For example:
#XmlRootElement(name="foo")
public class Foo {
#XmlElement
public List<Bar> getBars() {
return this.bars;
}
}
#Path("foo")
public FooResource {
#GET
public Foo getFoo() {
return theFoo;
}
}
When bars has no elements, the result serializes as null and when it contains a single element, it serializes as that element, not an array containing a single element. Is there a way to get these to always serialize as an array?
For reference, I'm using Jersey 1.10 and Jackson 1.9.2.
I am pretty sure that you are not actually using Jackson ("POJO" variant of JSON serialization), since Jackson would not convert single-element arrays or lists to anything else. So you are probably using one of legacy output methods (like jettison); meaning that if you configure system to use POJO mapping it should just work.
I wrote a blog post ages ago about forcing Jersey to serialize single element arrays correctly, not sure if it's out-dated now (its from mid-2010!), but it might be of use.
Note the blog comment from Brill Pappin on the blog demonstrating a different approach which means upgrading the Jettison library that you are using.
In short you can write a custom JaxbContextResolver that looks a little like:
#Provider
#Component
public class JAXBContextResolver implements ContextResolver {
private JAXBContext context;
public JAXBContextResolver() throws Exception {
MappedBuilder builder = JSONConfiguration.mapped();
builder.arrays("invite");
builder.rootUnwrapping(true);
this.context = new JSONJAXBContext(builder.build(), Payload.class);
}
public JAXBContext getContext(Class objectType) {
return (Payload.class.equals(objectType)) ? context : null;
}
}
For clarity, my payload class looked a little like
#XmlRootElement(name = "response")
#XmlAccessorType(XmlAccessType.FIELD)
public class Payload {
#XmlElement(name = "invite")
List invites;
... etc.
Regarding stopping Jackson serializing bean properties as null, see my previous answer here, about using annotations to change that behaviour.
I managed to solve JSON array "bug" in recent Jersey json library (v1.14 Sep 2012). Secret ingredient is JSONConfiguration and ContextResolver magic. See my following post it has a full code example, customized ContextResolver and rest Application class might be somewhat fuzzy logic in first look.
How to serialize Java primitives using Jersey REST
Primitives and zero or single-element List array are properly serialized to JSON document.
Yes, we also faced the same issue. Jackson cannot serialize list with 0 or single element to json array. So we tried to use Json's ObjectMapper to convert POJO object to String. It will serialize java List to json array irrespective of number of elements in List (0 or 1 or > 0). The code would look like :
request = new ObjectMapper().writeValueAsString(pojo);
where request is of type Object. This will not affect response. You can give a try.

Categories

Resources