Initialize objects with Lombok - java

I have the following object:
#Data
#AllArgsConstructor
#NoArgsConstructor
public class MyComplexObject implements Serializable {
private static final long serialVersionUID = 1L;
private OuputObject ouput;
}
#Data
#AllArgsConstructor
#NoArgsConstructor
public class OuputObject implements Serializable {
private static final long serialVersionUID = 1L;
private InputObject input;
}
#Data
#AllArgsConstructor
#NoArgsConstructor
public class InputObject implements Serializable {
private static final long serialVersionUID = 1L;
private List<String> example;
}
When instantiating the object, the object is not initialized "OuputObject" and is always NULL. Why is the OuputObject object and the InputObject object not instantiated or initialized?
When I do a: getInputObject () I get a NullPointerException
(This is an example, it's fake data)

#Data creates getters and setter, #AllArgsConstructor creates constructor for all the fields, and #NoArgsConstructor creates default constructor. To have your object initialised, you need to use constructor, e.g.
MyComplexObject mco = new MyComplexObject(new InputObject());

Lombok doesn't initialize properties.
The annotation #Data only generates getters and setters for the class properties and overrides the toString, hashCode and equals method.
#Data
public class MyClass {
private String myString;
}
Generates the following code:
public class MyClass {
private String myString;
public String getMyString() {
return myString;
}
public void setMyString(String myString) {
this.myString = myString;
}
// equals, hashcode, toString
}
Have a look at the documentation

Related

Q class not generating by query-dsl for nested embedded objects inside document class in spring data

I have below collection and embedded documents
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#JsonInclude(JsonInclude.Include.NON_NULL)
#Document(collection = "person_details")
public class PersonDetails {
#MongoId(FieldType.OBJECT_ID)
private String managerId;
.
.
#QueryInit("addressDetails.*")
private List<ContactDetails> contactDetails;
.
}
And ContactDetails.java looks like below:
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ContactDetails {
private AddressDetails addressDetails;
private StateDetails stateDetails;
}
StateDetails look like below:
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#JsonInclude(JsonInclude.Include.NON_NULL)
#Document(collection = "statedetails")
public class StateDetails {
#MongoId(FieldType.OBJECT_ID)
private String stateId;
private String stateName;
}
And AddressDetails look like below:
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#JsonInclude(JsonInclude.Include.NON_NULL)
public class AddressDetails {
private String address;
#Field(targetType = FieldType.STRING)
private AddressTypeEnum addressType;
}
After building , I am not getting Q class for AddressDetails, due to which I am facing issues in building Predicate. Below is my generated QPersonDetail class
#Generated("com.querydsl.codegen.DefaultEntitySerializer")
public class QPersonDetails extends EntityPathBase<PersonDetails> {
private static final long serialVersionUID = 184263140L;
private static final PathInits INITS = new PathInits("*", "contactDetails.addressDetails.*");
public static final QPersonDetails managerDetails = new QPersonDetails("managerDetails");
public final ListPath<ContactDetails, QContactDetails> contactDetails = this.<ContactDetails, QContactDetails>createList("contactDetails", ContactDetails.class, QContactDetails.class, INITS.get("contactDetails"));
public QPersonDetails(String variable) {
this(PersonDetails.class, forVariable(variable), INITS);
}
public QPersonDetails(Path<? extends PersonDetails> path) {
this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS));
}
public QPersonDetails(PathMetadata metadata) {
this(metadata, PathInits.getFor(metadata, INITS));
}
public QPersonDetails(PathMetadata metadata, PathInits inits) {
this(PersonDetails.class, metadata, inits);
}
}
And below is generated QContactDetails:
#Generated("com.querydsl.codegen.DefaultEmbeddableSerializer")
public class QContactDetails extends BeanPath<ContactDetails> {
private static final long serialVersionUID = 1039545873L;
private static final PathInits INITS = PathInits.DIRECT2;
public static final QContactDetails contactDetails = new QContactDetails("contactDetails");
public final SimplePath<AddressDetails> addressDetails = createSimple("addressDetails", AddressDetails.class);
public QContactDetails(String variable) {
this(ContactDetails.class, forVariable(variable), INITS);
}
public QContactDetails(Path<? extends ContactDetails> path) {
this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS));
}
public QContactDetails(PathMetadata metadata) {
this(metadata, PathInits.getFor(metadata, INITS));
}
public QContactDetails(PathMetadata metadata, PathInits inits) {
this(ContactDetails.class, metadata, inits);
}
}
I referred many threads including
https://querydsl.com/static/querydsl/5.0.0/reference/html/ch03s03.html but still not able to figure out issue. Even i tried with
#QueryInit("*.*")
annotation on contactDetails, above. Any idea, where I am missing. I dont want AddressDetails to be annotated as #Document.
I found this thread Querydsl 4 StringExpression of a field inside a SimplePath
This solves theproblem, but I am still confused with the concept, how #QueryEmbeddable works

How to reference a list of objects like that is not a DynamoDB table

I have a table with a string attribute that is my hask key and another attribute that is of type list, but when doing some operation whose query goes through this list an error is returned that the list object must have the #DynamoDBTable annotation but the object is not a table.
Error: "com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: class com.beasu.appbeasu.adapter.db.entity.ParesEntity not annotated with #DynamoDBTable
Look:
#DynamoDBTable(tableName = "tb_01_pare")
#ToString
#EqualsAndHashCode
public class DataPareEntity {
private String codDist;
private List<PareEntity> pares;
#DynamoDBHashKey(attributeName = "cod_dist")
public String getCodDist() {
return codDist;
}
public void setCodDist(String codDist) {
this.codDist= codDist;
}
#DynamoDBAttribute(attributeName= "obt_lis_pares")
public List<ParesEntity> getPares() {
return pares;
}
public void setPares(List<PareceresEntity> pareceres) {
this.pareceres = pareceres;
}
}
#AllArgsConstructor
#NoArgsConstructor
#DynamoDBDocument
public class ParesEntity {
private String codDist;
private String numFun;
private String txtJus;
private String indDec;
private String dateHr;
} // getters and setters...
If anyone knows the reason for this problem and can let me know I would be very grateful.

Using SuperBuilder to extend parent class using Lombok

I had a DTO that was using Lombok functionaliy as shown below.But now due to some requirement I had to extend my DTO to a parent class which looks like below.How can I do minimal change in my DTO to support that.I tried using #SuperBuilder annotation but it failed.
DTO Before:
#Getter
#ToString
#EqualsAndHashCode
#Builder(toBuilder = true)
#AllArgsConstructor(access = AccessLevel.PRIVATE)
public class RequestMessage {
private final String name;
}
Parent Class that needs to be extended
#Data
#SuperBuilder(toBuilder = true)
#JsonDeserialize(builder = MyDTO.Builder.class)
public abstract class MyDTO implements Serializable {
#JsonIgnore private final ObjectMapper objectMapper = new ObjectMapper();
protected String myAccountId;
protected MyDTO() {}
public static int hashCode(Object... objects) {
return Arrays.deepHashCode(objects);
}
public static boolean equal(Object o1, Object o2) {
// implementation of equals method
}
public abstract String emitSerializedPayload() throws JsonProcessingException;
#JsonPOJOBuilder(withPrefix = "")
protected abstract static class Builder<T extends MyDTO, B extends Builder<T, B>> {
protected T dtoInstance;
protected B builderInstance;
public Builder() {
dtoInstance = createDtoInstance();
builderInstance = returnBuilderInstance();
}
protected abstract T createDtoInstance();
protected abstract B returnBuilderInstance();
public B myAccountId(String accountId) {
dtoInstance.myAccountId = accountId;
return builderInstance;
}
public T build() {
return dtoInstance;
}
}
}
I tried to build RequestMessageClass manually and it works fine but there are lot of classes in my application and I dont want to change them manually, how can I change my existing RequestMessage class with annotations or some minimum change to get it working.
This is what I tried but I am getting compilation error when doing this
RequestMessage.Builder().name(myName).myAccountId(myAcId).build();
What I tried is like shown below:
#Getter
#ToString
#EqualsAndHashCode(callSuper = true)
#SuperBuilder(toBuilder = true)
#AllArgsConstructor(access = AccessLevel.PRIVATE)
public class RequestMessage extends MyDTO {
private final String name;
#Override
public String emitSerializedPayload() throws JsonProcessingException {
// TODO Auto-generated method stub
return null;
}
}
You shouldn't mix lombok #Builder with static inner Builder class. If it is possible to get rid of Builder class, the next code should work.
RequestMessage:
#Getter
#ToString
#EqualsAndHashCode(callSuper = true)
#SuperBuilder(toBuilder = true)
#AllArgsConstructor(access = AccessLevel.PRIVATE)
public class RequestMessage extends MyDTO {
private final String name;
#Override
public String emitSerializedPayload() throws JsonProcessingException {
return null;
}
public RequestMessage(String myAccountId, String name) {
super(myAccountId);
this.name = name;
}
}
MyDTO:
#Data
#SuperBuilder(toBuilder = true)
public abstract class MyDTO implements Serializable {
#JsonIgnore private final ObjectMapper objectMapper = new ObjectMapper();
protected String myAccountId;
protected MyDTO() {}
public MyDTO(String myAccountId) {
this.myAccountId = myAccountId;
}
public static int hashCode(Object... objects) {
return Arrays.deepHashCode(objects);
}
public static boolean equal(Object o1, Object o2) {
// implementation of equals method
return false;
}
public abstract String emitSerializedPayload() throws JsonProcessingException;
}
Test:
#Test
void name() {
String myName = "myName";
String myAccountId = "myAccountId";
var request = RequestMessage.builder().name(myName).myAccountId(myAccountId).build();
System.out.println("request = " + request);
RequestMessage requestMessage = new RequestMessage(myAccountId, myName);
}

Jackson ignore serialization of top-level field if all its nested fields are null

I am using Jackson ObjectMapper to serialize a POJO. I have nested fields in the POJO. Eg: serializing class MyClass
public class MyClass {
private A a;
private int i;
//getters and setters
}
public class A {
private String s;
//getters and setters
}
I want that if String s is null, the entire property A does not get serialized. That is, if String s is null, I want the output to be:
{"myClass":{"i":10}}
But I am getting {"myClass":{"A":{},"i":10}} as the output instead.
I have set NON_EMPTY for serialization inclusion (mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)), but it doesn't solve the problem
AFAIK you cannot do this with standard annotations, but changing MyClass.getA() method in this way you should do the trick.
public A getA() {
if (a.getS() == null)
return null;
return a;
}
Generate hashCode() and equals() in the desired class.
public class A extends Serializable{
private String s;
// getters and setters
// hashCode() and equals()
}
Set an Include.CUSTOM in your parent class.
#JsonInclude(value = Include.CUSTOM, valueFilter = A.class)
public class MyClass extends Serializable {
private A a;
private int i;
//getters and setters
}
All empty objects will be excluded and the output will be: {"myClass":{"i":10}}
You need just to add #JsonInclude(JsonInclude.Include.NON_NULL)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class MyClass implements Serializable {
private A a;
private int i;
//getters and setters
}
public class A implements Serializable{
private String s;
//getters and setters
}

Constructor method must contain all instance variables

Many times I'm faced with a class which constructor method must contain list of arguments that is identical with the list of class instance variables.
As you see in the example there is "SOME" code to make this hapend.
I'm wondering how can I make this process less painful?
Example:
public class VimeoUser extends Schema {
#Getter #Setter private String uri;
#Getter #Setter private String name;
#Getter #Setter private String link;
#Getter #Setter private String location;
#Getter #Setter private String bio;
#Getter #Setter private String createdTime;
#Getter #Setter private String account;
#Getter #Setter private Map<String,Integer> statistics = new HashMap<>();
#Getter #Setter private List<Website> websites = new ArrayList<>();
#Getter #Setter private List<Portrait> portraits = new ArrayList<>();
public VimeoUser(
String uri,
String name,
String link,
String location,
String bio,
String createdTime,
String account,
Map<String,Integer> statistics,
List<Website> websites,
List<Portrait> portraits){
this.uri = uri;
this.name = name;
this.link = link;
this.location = location;
this.bio = bio;
this.createdTime = createdTime;
this.account = account;
this.statistics = statistics;
this.websites = websites;
this.portraits = portraits;
}
}
It is possible to use a pattern named Builder. It is explained in this question
Basically it works as following:
Create an inner static class Builder
Create a private constructor that take as an argument an object of type Builder
In the Builder class add methods that set a single value and returns this (current reference to instance of the Builder class)
In the body of the constructor of your class use the values passed in the Builder to set each property
add a method build in the Builder that calls the private constructor of your class
Here is an example:
public class NutritionalFacts {
private int sodium;
private int fat;
private int carbo;
public class Builder {
private int sodium;
private int fat;
private int carbo;
public Builder(int s) {
this.sodium = s;
}
public Builder fat(int f) {
this.fat = f;
return this;
}
public Builder carbo(int c) {
this.carbo = c;
return this;
}
public NutritionalFacts build() {
return new NutritionalFacts(this);
}
}
private NutritionalFacts(Builder b) {
this.sodium = b.sodium;
this.fat = b.fat;
this.carbo = b.carbo;
}
}
and to use it do the following:
NutritionalFacts nutritionalFacts = new NutritionalFacts.Builder()
.fat(200).carbo(50).build();
Using this pattern instead of pojo with setter and getter is useful because it is possible to use it also to build immutable objects (objects with all final fields). An immutable object is useful if you need to share it on a multithreaded environment because it is not necessary to synchronize the access to it.
Additionally it is possible to add some controls in the build method to be sure that all fields are setted as expected.
I guess writing pojos for database modelling does not necessarily needs constructor other than default no-arg constructor. If anyway required in some situations, Getters and setters can be used.
Builder pattern
If you want create a object with more readable way, you can use a simple builder pattern. Lombok support this such as #Getter or #Setter. You just add #Builder annotation and everything should works fine.
#Getter
#Builder
public class SomeClass {
private final String valueOne;
private final String valueTwo;
}
And then you can create object in this way.
SomeClass someClass = SomeClass.builder()
.valueOne("one")
.valueTwo("two")
.build();
Fluent accessors method
Alternative way to create a class is using #Accessors annotation with fluent = true. Then you can create a empty object and set the value what you needed in simple way.
#Getter
#Setter
#Accessors(fluent = true)
public class SomeClass {
private String valueOne;
private String valueTwo;
}
Simple sample using this way.
SomeClass someClass = new SomeClass()
.valueOne("one")
.valueTwo("two");
I see you are already using Lombok. There is a #AllArgsConstructor class-level annotation that will generate the constructor for you. If you want the default constructor, too, use #NoArgsConstructor additionally.
More info on the constructor-generating annotations here.

Categories

Resources