Ignore JSON attribute cases declared with #JsonProperty with Spring RestTemplate - java

I use #JsonProperty to serialize data from a JSON through Spring RestTemplate's exchange.
#JsonProperty("ip_address")
public String ipAddress;
#JsonProperty("port")
public Integer port;
I need this property to recognize both upper and lowercase versions of the attribute names i.e. "ip_address" and "IP_ADDRESS" set in #JsonProperty should be recognized.
I have tried the following and none worked:
#JsonFormat(with=JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) applied on a class level does not work with existing issue reported in GitHub. Also does not work when applied to each attribute in the model class.
use MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES on an ObjectMapper bean.
This example using ObjectMapper and RestTemplate also didn't work even with a combination code with the example on the item before.
All three just have null values for their respective attributes because I disabled error on unknown attributes (a.k.a. the different letter case) for the template.

You can tell jackson to convert all your property names into e.g. SNAKE_CASE variants and set your #JsonProperty accordingly:
Example:
in spring boot set the property in application.properties
spring.jackson.property-naming-strategy=SNAKE_CASE
or you can enable it for just your single class and annotate the class with:
#JsonNaming(PropertyNamingStrategy.SNAKE_CASE.class)
and then set #JsonProperty:
#JsonProperty(vale="ip_address")

I was able to get this working without changing my original pojo class #JsonProperty configs. Using the Object Mapper and Rest Template example you linked to but instead of a Property Naming strategy use the case insensitive mapper feature
ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);

For Spring Boot App to Ignore Case for JSON attributes names:
Step 1: Make sure your POJO/Domain/Model class has a constructor with respective parameters, and remove any zero arg constructor.
Step 2: Add Jackson lib as a dependency
Ex:
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>2.6.5</version>
</dependency>
Step 3: Enable in application.properties file as below
spring.jackson.mapper.accept_case_insensitive_properties=true

Related

Jackson YAMLFactory, how to allow/disable single quotes at a field level?

I'm using Spring Boot to return YAML via a controller. I have created a Jackson YAMLFactory ObjectMapper. However the consumer of the YAML from the endpoint is fussy about certain fields having single quotes but the majority should not, this is not something I can change.
I have my ObjectMapper set up as such:
public MappingJackson2YamlHttpMessageConverter yamlHttpMessageConverter() {
return new MappingJackson2YamlHttpMessageConverter(new ObjectMapper(new YAMLFactory()
.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES))
.enable(SerializationFeature.INDENT_OUTPUT));
}
This successfully returns me YAML with no double quotes which was the default. I can not however work out how to allow specific fields to be enclosed by single quotes. I have tried annotating the Getters with JsonRawValue and then adding the quote into the value set in the field:
#JsonRawValue
public String getSonarProjectKey() {
return sonarProjectKey;
}
But of course this does not work with YAML and I get an exception.
So I'm unsure about how to achieve this requirement.

Conflicting setter definition for field name starting with set

We have a pojo generated from yml which has #JsonProperty defined on the getter. This is based on maven plugin for openapi. For one such yml, we have a field settlementType. We can't change the name as this is the field to be sent to the vendor in the rest api call. When using jackson's ObjectMapper to deserializa the object, we get the following error -
Conflicting setter definitions for property "settlementType":
settlementType(1 param) vs setSettlementType(1 param).
I tried for a mixin class.
public class SettlementTypeMixin {
#JsonProperty("settlementType"
String settlementType;
#JsonIgnore
public void setSettlementType(String settlementType) {
this.settlementType = settelementType;
}
}
I added the mixin to the mapper using addMixinAnnotations method. But I don't see any change in the behavior.
I also tried setting the fieldVisibility, getterVisibility, setterVisibility and CreatorVisibilities as well. There are other types as well which the yml needs and at the end I have to enable the visibility for all the types mentioned below.
I am not able to get the object mapped using jackson. Please let me know if there is a way out for this.

Supply Polymorphic De-serialization/Serialization parameters to REST endpoint without changing POJOs

I am working on a JAX-RS application, where endpoints Consume and Produce JSON type data. And I am using Jackson for that purpose.
As I know one of the ways to handle Polymorphic behavior in Jackson is to use #JsonTypeInfo and #JsonSubTypes on POJOs.
But in my case POJOs are not part of code, they're embedded in a JAR file and I can't edit them.
Is there any way where I can specify this info to Jackson externally without POJO annotations ?
Please point me to the right direction of this has already been discussed earlier.
Is there any way where I can specify this info to Jackson externally without POJO annotations?
Using annotations is still a valid approach if you consider mix-in annotations.
When modifying the source code is not an option, you can use mix-in annotations to add Jackson annotations to a bean. You can think of it as kind of aspect-oriented way of adding more annotations during runtime, to augment statically defined ones.
First define a mix-in annotation interface or class:
#JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "class")
public interface FooMixIn {
}
Then configure ObjectMapper to use the defined interface as a mix-in for your POJO:
ObjectMapper mapper = new ObjectMapper().addMixIn(Foo.class, FooMixIn.class);
All annotation sets that Jackson recognizes can be mixed in. For more details, have a look at the Jackson documentation.

How do I use JAXB annotations with Spring RestTemplate?

I'm trying to automatically deserialize XML formatted response using Spring's RestTemplate. I'm using Jackson's jackson-dataformat-xml module, for which Spring Boot is set to auto-configure. I want to use JAXB annotations in the class I want to deserialize to, but it won't seem to work. Here's a sample of what I want the class to look like:
#XmlRootElement(name="Book")
public class Book {
#XmlElement(name="Title")
private String title;
#XmlElement(name="Author")
private String author;
}
This is based on the following XML sample:
<Book>
<Title>My Book</Title>
<Author>Me</Author>
</Book>
However, with class annotated like that above, the fields are always set null. I did some experiments and found out that the deserialization works if I use Jackson's #JsonProperty to annotate the child elements:
#XmlRootElement(name="Book")
public class Book {
#JsonProperty("Title")
private String title;
#JsonProperty("Author")
private String author;
}
It works, but somehow I feel like it's kind of awkward. Is there a way to get the JAXB annotations work like in my first example?
Jackson provides jackson-module-jaxb-annotations module for the XML databinding to work with JAXB annotations. However, I'm not sure how to setup the ObjectMapper being used by RestTemplate to use this module.
To address this issue, I needed to register an instance of JaxbAnnotationModule to every ObjectMapper used by converters added to Spring's RestTemplate. The class is included in Jackson's jackson-module-jaxb-annotations module, which I added to my build through Gradle.
With the dependency added to my project, what I did next was to configure the RestTemplate used by my application. The ObjectMapper instances are being used by MappingJackson2XmlHttpMessageConverters configured automatically by Spring. I had to register JaxbAnnotationModule instance to each ObjectMapper used in every converter, so the first task was to find all MappingJackson2XmlHttpMessageConverters using:
//create module
JaxbAnnotationModule jaxbAnnotationModule = new JaxbAnnotationModule();
restTemplate.getMessageConverters().stream().filter(converter -> {
return converter instanceof MappingJackson2XmlHttpMessageConverter;
})
Once I had all the relevant converters, I then registered the module to each of their ObjectMappers:
forEach(converter -> {
((MappingJackson2XmlHttpMessageConverter) converter)
.getObjectMapper()
.register(jaxbAnnotationModule);
});
I suspect that in second case Spring simply ignores root level JAXB annotation, because by default Jackson will resolve name of the class properly.
In order to use JAXB annotations you have to use library jackson-xc
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId>
</dependency>
These artilces may be also useful:
1) http://wiki.fasterxml.com/JacksonJAXBAnnotations
2) http://springinpractice.com/2011/12/06/jackson-json-jaxb2-xml-spring
3) How can we configure the internal Jackson mapper when using RestTemplate?
If solution by #Psycho Punch still not working for you, This is another alternative:
add com.fasterxml.jackson.dataformat:jackson-dataformat-xml dependency.
use XmlMapper instead of ObjectMapper to your MappingJackson2XmlHttpMessageConverter. For example:
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.registerModule(new JaxbAnnotationModule());
forEach(converter -> {
((MappingJackson2XmlHttpMessageConverter) converter).setObjectMapper(xmlMapper)
});
HTH
If someone still have to deal with this kind of issue, Springboot provide an elegant solution :
Any beans of type com.fasterxml.jackson.databind.Module are automatically registered with the auto-configured Jackson2ObjectMapperBuilder and are applied to any ObjectMapper instances that it creates. This provides a global mechanism for contributing custom modules when you add new features to your application.
So adding this in one of your configuration class should be enough:
#Bean
public Module jaxbModule() {
return new JaxbAnnotationModule();
}
Source: https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-customize-the-jackson-objectmapper

Jackson with JSON: How can I make it ignore additional properties but error on incomplete json?

I know how I can make Jackson to ignore any additional fields in Json, simply by adding
#JsonIgnoreProperties(ignoreUnknown = true):
#JsonIgnoreProperties(ignoreUnknown = true)
class MyDto {
int someField;
}
But side-effect of this is that Jackson now also accepts incomplete JSON and fills missing fields with nulls.
How can I enforce Jackson to require every field to exist in json and still ignore additional fields in it?
Thank you.
Jackson explicitly does NOT validate logical POJO contents; instead, you are recommended to use Bean Validation (JSR-303, see http://en.wikipedia.org/wiki/Bean_Validation) API implementation; for example one provided by Hibernate project: http://hibernate.org/validator/
This is the approach many frameworks take; for example, DropWizard supports data-binding using Jackson, and then validation (after data-bind, before business logic run) using Bean Validation.
In order to check if all properties needed are available you need to add the required anotation to the property.
#JsonProperty(value = "response", required = true)
public SomeResponse response;

Categories

Resources