Conflicting setter definition for field name starting with set - java

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.

Related

Field mapping with MapStruct by JsonProperty annotation

In my current project the names of the model class fields are German. The fields are all annotated with #JsonProperty for the English translation of the names. E.g. #JsonProperty(value = "operation"). Is there a way in the configuration that the mapping of the fields is done using the JsonProperty annotation?
Example:
public class Auftrag {
#JsonProperty(value = "orderType")
private String auftragsart;
...
}
public class OrderDto {
private String orderType;
}
MapStruct uses the Java Bean convention to detect the properties. This means that it looks in the getters and setters.
Out-of-the-box you cannot use the #JsonProperty. However, you can create your own AccessorNamingStrategy that will provide the properties based on #JsonProperty. The AccessorNamingStrategy gives you access to the Abstract syntax tree, which means you can look for fields in types, check their annotations and check their values.
Keep in mind that MapStruct will only ask to get the property for a method, so you would need to get the property name, then find the field in the type, then look for the #JsonProperty annotation and its value.
You can read more about the AccessorNamingStrategy here in the documentation.

Java Polymorphic Json Deserialization

I am using jackson as part of serializing and deserializing in my project (Spring Java).
In normal scenarios where I have interface(contract) acting as field in POJO,
then I use #JsonTypeInfo and #JsonSubTypes to achieve deserialization in polymorphic cases.
But, right now, I have scenariio something like this:
public class classA {
private contractA fieldA;
//constructor and getter-setters.
}
then,
public interface contractA {
}
and finally,
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(/* concrete-class1 as name-value */),
#JsonSubTypes.Type(/* concrete-class2 as name-value */),
})
public interface contractB extends contractA {
//contract methods.
}
Now, when classA is passed as controller request body and I pass fieldA as concrete-class1 or concrete-class2,
JsonSubTypes are not being used by jackson to deserialize into one of them.
The reason why I did this and had two contracts is due to package dependencies. contractB
is in different package as of contractA's.
How can I configure on contractA using jackson that this class has its JsonSubTypeInfo specified in its subclasses.
Or, any other libraries or approaches are also welcomed.
Thank you !
This problem is later on solved by introducing our own custon JsonTypeInfo.
When the application is under deployment, we fetch all subclasses which is present in the JsonTypeInfo annotation (jackson like custom annotaion) and maintain a data-structure, that will be used while serializing and deserializing. This process is somewhat similar to the Jackson one (in addition to lookup for nested hierarches as well).

Builder pattern when retrieving entity from DB w/ spring boot reactor & mongo

I have the following bean that describes a mongo document, and that uses lombok:
#JsonDeserialize(builder = MyClass.MyClassBuilder.class)
#Builder(toBuilder = true)
#Value
public class MyClass {
private final String id;
#Default
private final String field = "defaultValue";
#JsonPOJOBuilder(withPrefix = "")
public static class MyClassBuilder {}
}
When deserializing {"id": "document"} with jackson, I end-up with a bean containing both id=document and field=defaultValue because it used the builder that provide a default value for the field.
Now what I want to do, is to have the defaultValue set for documents coming out of the database (coming from ReactiveMongoTemplate). But it seems to use the all args constructor even if I set it private (or some reflect black magic)
So the main question is: is it possible to tell spring to use the builder to build the bean when coming out of the database?
You are not going to be able to use your custom serialiser because when I go through the source code of MappingMongoConverter in spring mongodb (debugged it with a sample app) , I see only the following steps.
Once the value from db is available as org.bson.Document, MappingMongoConverter.java is looking to create your entity object.
First, it checks if you have any custom converters registered and if you have it, then use it. So one option is to use a custom converter registered.
If there is no custom converters registered, it goes and find the PersistenceConstructor and use it. I had an object with 3 constructors (no param, one param, and all param) and it chose my no param constructor.
However, if I annotate a constructor with #PersistenceConstructor, it is choosing that constructor. So could follow this approach but then you have to keep String field un-initialised and getting initialised differently in each constructor
MappingMongoConverter.java
conversions.hasCustomReadTarget
persistenceConstructor

Ignore JSON attribute cases declared with #JsonProperty with Spring RestTemplate

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

Jackson equivalent to #XmlSeeAlso

I am writing a RESTful web service using Java and Jersey, where the service will accept either XML or JSON inputs. Jackson is used as the JSON deserializer, and integrated into the Jersey config.
One of the endpoints is a POST request to a URL, where the content can be one of several different Java classes, and there is a common base class. These classes - with XML annotations - are:
#XmlRootElement(name = "action")
#XmlAccessorType(XmlAccessType.NONE)
#XmlSeeAlso({ FirstAction.class, SecondAction.class, ThirdAction.class })
public abstract class BaseAction {
}
#XmlRootElement(name = "first-action")
#XmlAccessorType(XmlAccessType.NONE)
public class FirstAction extends BaseAction implements Serializable {
}
// Likewise for SecondAction, ThirdAction
In my resource I can declare a method like:
#POST
#Path("/{id}/action")
public Response invokeAction(#PathParam("id") String id, BaseAction action) {...}
Then I can POST an XML fragment that looks like <firstAction/> and my method will be invoked with a FirstAction instance. So far so good.
Where I'm struggling is getting the JSON deserialization to work as seamlessly as the XML deserialization. Where the #XmlSeeAlso annotation was critical to get the XML deserialization working properly, it seemed that the equivalent for JSON was #JsonSubTypes. So I annotated the classes like this:
// XML annotations removed for brevity, but they are present as in the previous code snippet
#JsonSubTypes({ #JsonSubTypes.Type(name = "first-action", value = FirstAction.class),
#JsonSubTypes.Type(name = "second-action", value = SecondAction.class),
#JsonSubTypes.Type(name = "third-action", value = ThirdAction.class) })
public abstract class BaseAction {
}
#JsonRootName("first-action")
public class FirstAction extends BaseAction implements Serializable {
}
// Likewise for SecondAction, ThirdAction
I then feed it my test input: { "first-action": null } but all I can get is:
"org.codehaus.jackson.map.JsonMappingException: Root name 'first-action' does not match expected ('action') for type [simple type, class com.alu.openstack.domain.compute.server.actions.BaseAction]"
Unfortunately since I'm trying to be compatible with someone else's API I can't change my sample input - { "first-action": null } has to work, and deliver to my method an object of class FirstAction. (The action doesn't have any fields, which is why null shouldn't be a problem - it's the type of the class that's important).
What's the correct way to have the JSON deserialization work in the same way as the XML deserialization already is?
If you are using Jackson, you are looking for #JsonTypeInfo and #Type . Please see here for more information
JSON does not work the way XML does, so the solution is not identical.
What you need to use is (like the other answer said), #JsonTypeInfo. That only triggers inclusion and use of the type identifier. If so, then '#JsonSubTypes` will be of use in deserialization.
The reason this indicator must be used is simple: if you have more than one alternative type to deserialize to, there must be something to differentiate.
Note, too, that this does NOT have to be a property -- while most users choose "As.PROPERTY" inclusion, it is not (IMO) the best way. "WRAPPER_OBJECT" may be what you are looking for, as it adds an extra intermediate JSON property, which is somewhat similar to what XML does.
I investigated the use of #JsonTypeInfo but ran into problems because I could not alter the input format. The parser absolutely had to be able to handle input { "first-action":null }. This ruled out the possibility of adding an #type or #class property. Using a wrapper object may have worked, but it choked on the null payload.
A crucial point was that I was using the UNWRAP_ROOT_PROPERTY configuration option. Jackson was absolutely insisting on finding an action property and I could not get it to consider anything else. So, I had to selectively disable UNWRAP_ROOT_PROPERTY for certain domain objects, so that Jackson would be open to parsing alternatives. I modified the project's ContextResolver.getContext(...) implementation to check for a #JsonRootName annotation - since this only has meaning if wrapping is enabled, I used the presence of this annotation to determine whether to return an object mapper configured with root property wrapping on, or off.
At this stage, I might have been able to use #JsonTypeInfo(include=JsonTypeInfo.As.WRAPPER_OBJECT, ...), except for the issue with the null payload mentioned above (this is used to indicate that the child object has no properties - if the spec I was working from had given an empty object {} instead then there would not be a problem). So to proceed I needed a custom type resolver.
I created a new class that extended org.codehaus.jackson.map.TypeDeserializer, with the purpose that whenever Jackson is called to deserialize a BaseAction instance, it will call this custom deserializer. The deserializer will be given a subtypes array, which for BaseAction maps first-action, second-action, etc. to FirstAction.class, etc. The deserializer reads the input stream for the field name, then matches the name to a class. If the next token is an object, then it finds and delegates to the appropriate deserializer for that class, or if it is null it finds the no-args constructor and invokes it to get an object.
A class that implements org.codehaus.jackson.map.jsontype.TypeResolverBuilder is needed that can build an instance of this previous class, and then the TypeResolverBuilder is given as a #JsonTypeResolver annotation on the BaseAction class.

Categories

Resources