convert object to xml using jackson-dataformat-xml with default values - java

I am using the jackson-dataformat-xml dependency to convert my object to xml.
Its initializing the parent class properties to default value in the output xml but properties of nested class is not getting initialized(in the output xml nested class properties are not coming).
Below is the code which tried ,can anyone pls look into this issue, if am missing something.
Below is my class structure
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
#Builder(toBuilder = true)
public class Settings {
private SettingsBlock settingsBlock //nested class;
private int test1=10;
private int test2;
}
below is the nested class
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
#Builder(toBuilder = true)
public class SettingsBlock {
private Boolean block1=true;
private Boolean block2=;
}
Building the xml
class Build XML{
XmlMapper xmlMapper = new XmlMapper()
String xml = mapper.writeValueAsString(new Settings())
}
Output I am getting currently
<Settings>
<test1>1</test1>
<test2>0</test2>
<SettingsBlock/>
</Settings>
Output which I wanted is
<Settings>
<test1>1</test1>
<test2>0</test2>
<SettingsBlock>
<block1>true</block1>
<block2>false</block2>
<SettingsBlock/>
</Settings>
pom.xml
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>

SettingsBlock is not instantiated, that's why jackson can't get any property of this object! If you want to have the default values of SettingsBlock, you have to instantiate it:
public class Settings {
private SettingsBlock settingsBlock = new SettingsBlock();
private int test1=10;
private int test2;
}

Related

Deserializing abstract generic class in Java with Jackson

I am sending a POST request with the Sample JSON request body:
"name" : "jeff",
"country" : "US",
"content" : {
"subject" : "Test-Subject",
"body" : "Test-body"
}
The class that is this JSON is deserialized into:
#Introspected
#Builder
#Data
public class Template<T extends Content> {
String name;
String country;
T content;
}
Content looks like this:
#Introspected
#Superbuilder
#Getter
#EqualsAndHashCode
#NoArgsConstructor
#AllArgsConstructor(onConstructor_ = #JsonCreator)
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, property="content")
#JsonSubTypes(#JsonSubTypes.Type(value = EmailContent.class, name="EmailContent"))
public abstract class Content {
private String body;
}
This is what I want T content to deserialize into:
#Introspected
#Superbuilder
#Getter
#EqualsAndHashCode(callSuper = true)
#NoArgsConstructor
#AllArgsConstructor(onConstructor_ = #JsonCreator)
public class EmailContent extends Content {
private String subject;
}
I have everything working in Template EXCEPT the generic content type which is giving me trouble no matter what JsonTypeInfo I use. I am trying to deserialize it into an EmailTemplate class. I have other classes extending from content so I am not looking to use #JsonDeserialize.
Solved...it was due to using graalVM which supports partial reflection. I fixed this by adding the #ReflectiveAccess annotation alongside lombok's #Jacksonized annotation for deserializing builder types.

Jackson-databind deserializes JSON with missing property as "null" instead of default value

When deserializing a JSON string, missing properties are being set as "null" when they shouldn't be. Below is a POJO class:
#Builder
#Getter
#Setter
#JsonInclude(JsonInclude.Include.NON_NULL)
#NoArgsConstructor
#AllArgsConstructor
#ToString
#EqualsAndHashCode
static class MyPojo {
#JsonProperty(value = "OptionalProp", required = false, defaultValue = "")
#Builder.Default
#Nullable
#JsonSetter(value = "", nulls = Nulls.AS_EMPTY)
private String optionalProp = "";
#JsonProperty(value = "RequiredProp", required = false, defaultValue = "")
#Builder.Default
#Nullable
#JsonSetter(value = "", nulls = Nulls.AS_EMPTY)
private String requiredProp = "";
}
JSON String to deserialize:
{
"RequiredProp" : "test"
}
Here is the deserialization:
private final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private final myPojo = OBJECT_MAPPER.readValue(inputStream, MyPojo.class);
And here is the output:
MyPojo(optionalProp=null, requiredProp=test)
BUT creating the POJO with builder:
final MyPojo myPojo = MyPojo.builder()
.requiredProp("test")
.build();
Results in the following POJO:
MyPojo(optionalProp=, requiredProp=test)
I'm using:
Jackson-databind 2.12.x
Jackson-annotation 2.12.x
Jackson-core 2.12.x
Is there a minor version change from one of these packages that changes the behavior?
The problem stems from Lombok and not the actual Jackson stuff. Taking a look at the generated source code will give you a clear view of what's happening. Using Builder.Default seems to cause the issue as it apparently produces messed up code which removes the initializations you have in place. Removing the annotation restores proper behavior.
This seems to be an issue with Lombok and it is documented here. Removing the annotation should result in correct behavior.

#Accessors(fluent = true) doesnot work with Jakson

In Spring boot application with Lombok, I have pojo class AccountDTO
#Data
#Builder
#Accessors(fluent = true)
public class AccountDTO implements Serializable {
private String identification;
}
My project compiles fine. However, it throws an exception in its execution
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No
serializer found for class AccountDTO and no properties discovered to create
BeanSerializer
if I removed the annotation #Accessors(fluent = true), then it will work fine without any problems.
How can i make Lombok #Accessors(fluent = true) and Jackson work together ?
I stumbled on this question recently while encountering the same problem and the solution for me was to add and explicit #JsonProperty annotation on the getter generated by Lombok using:
#Getter(onMethod = #__(#JsonProperty)).
In your case, the class would look like this:
#Data
#Builder
#Accessors(fluent = true)
#Getter(onMethod = #__(#JsonProperty))
public class AccountDTO implements Serializable {
private String identification;
}

How to create an index programmatically for a dynamic Mongo collection? ( Java Spring Data MongoDB )

I need help with this, here is my document class:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Document(collection = "#{#dateService.getCurrentDate()}")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class LogDocument {
private ObjectId _id;
private String log;
private String key;
}
As you can see my collection name is dynamic depending on date, e.g. 2020-10-05.
I want to create a unique index on the key. HOW?
When the collection name is fixed I can simply do the following in the mongo Configuration class:
mongoTemplate.indexOps("{collection name}").ensureIndex(indexDefinition.unique());
but since the collection is dynamic, I need a way to trigger a PostConstruct for every time a new collection is created so that I can create the index.
The answer is simply using annotations
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
//For Compound index:
#CompoundIndexes({
#CompoundIndex(name = "key_app", def = "{'key' : 1, 'app': 1}")
})
#Document(collection = "#{#dateService.getCurrentDate()}")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class LogDocument {
private ObjectId _id;
private String log;
//For a unique index on one field:
// #Indexed(unique = true)
private String key;
private String app;
}

JsonDeserialize set inherited properties also when objectmapper readvalue

JsonDeserialize not working when objectmapper readvalue for inherited properties.
Vehicle Class
#Getter
#Setter
#JsonDeserialize(builder = Vehicle.VehicleBuilder.class)
#Builder(builderClassName = "VehicleBuilder", toBuilder = true)
public class Vehicle{
private String name;
private String noOfTyres;
#JsonPOJOBuilder(withPrefix = "")
public static class VehicleBuilder{
}
}
Car class
#Getter
#Setter
#JsonDeserialize(builder = Car.CarBuilder.class)
#Builder(builderClassName = "CarBuilder", toBuilder = true)
public class Car extends Vehicle {
private String carType;
#JsonPOJOBuilder(withPrefix = "")
public static class CarBuilder extends VehicleBuilder {
}
}
I don't want to create #NoArgsConstructor ,#AllArgsConstructor in both classes.
My issue when Car car = om.readValue(jsonValue,Car.class);
When I parse Json to java object the parent class properties are not setting properly.
As of now I'm using #NoArgsConstructor ,#AllArgsConstructor for work around for the use case.
Is there any way to use it along with #JsonDeserialize and #JsonPOJOBuilder?
The problem with the code is that it assumes that builders in inherited classes will set the parent properties as well. Unfortunately, they don't do that out of the box. However, this is something that can be achieved with Lombok but requires some additional code, as described in this post.
A complete solution could look as follows.
Parent Class
#Getter
#Setter
#JsonDeserialize
#Builder(builderClassName = "VehicleBuilder", builderMethodName = "vehicleBuilder")
public class Vehicle {
private String name;
private String noOfTyres;
}
Child Class
#Getter
#Setter
#JsonDeserialize(builder = Car.CarBuilder.class)
public class Car extends Vehicle {
private String carType;
#Builder
public Car(String name, String noOfTyres, String carType) {
super(name, noOfTyres);
this.carType = carType;
}
#JsonPOJOBuilder(withPrefix = "")
public static class CarBuilder extends VehicleBuilder {
}
}
Notice that the builder on the extending class is achieved by supplying a constructor with the #Builder annotation. Also take notice that the extending class does not set annotation parameter toBuilder=true as that will require access to parent properties which are private. This can be achieved by setting parent class properties to protected.

Categories

Resources