Exclude toString method generation that comes with Lombok #Data - java

I have a class that is annotated with #Data. But I want to exclude the toString() method and provide a custom toString.
I just defined a custom toString() method as I usually do if I was not using lombok and it seemed to work. Following is my example.
#Data
class SomeDTO {
private String property1;
private String property2;
private String someReallyHugeString;
#Override
public String toString(){
return "someReallyHugeString size is: " + someReallyHugeString.length()
+ "property1 = " + property1
+ "property2 = " + property2;
}
}
But wanted to know if this is the right way to exclude toString() from #Data and if there are any side effects I am missing.

Yes.
It is right way. You can provide any method generated by lombok. It will check that method already exist and skip generation.
The same rule applies to the constructor (any explicit constructor will prevent #Data from generating one), as well as toString, equals, and all getters and setters
by Lombok Docs

Just don't use #Data (but provide all the other annotations) that is has:
#Getter
#Setter
#RequiredArgsConstructor
#EqualsAndHashCode
SomeDTO { ....
public String toString(){....}
}
This way if you remove toString by accident, it will not be generated.

Related

Is there an order to create lombok's #Setter and #Builder?

I have a question about Lombok & MapStruct combination.
First, the class is as follows.
Person.java
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Person {
private String name;
#JsonProperty("name")
public void setCustomName(String name) {
this.name = "custom = " + name;
}
#JsonProperty("name")
public String getCustomName() {
return this.name;
}
public static class PersonBuilder {
public PersonBuilder customName(String name) {
return this.customName(name);
}
}
}
PersonMapper.java
#Mapper
public interface PersonMapper {
#Mapping(target = "customName", source = "personName")
#Mapping(target = "name", ignore = true)
Person toEntity(PersonRequest req);
}
I'm find that #Mapper generating code depends on dependencies order (Lombok, MapStruct)
If i use Lombok first and MapStruct second, 'XXMapperImpl.java' use setter method.
but use in reversed order, 'XXMapperImpl.java' use builder method.
// dependencies order: Lombok's next MapStruct
#Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2021-01-25T18:59:21+0900",
comments = "version: 1.3.1.Final, compiler: javac, environment: Java 14.0.2 (AdoptOpenJDK)"
)
public class PersonMapperImpl implements PersonMapper {
#Override
public Person toEntity(PersonRequest req) {
if ( req == null ) {
return null;
}
Person person = new Person();
person.setCustomName( req.getPersonName() );
return person;
}
}
but reversed order
// dependencies order: Lombok's next MapStruct
#Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2021-01-25T18:59:21+0900",
comments = "version: 1.3.1.Final, compiler: javac, environment: Java 14.0.2 (AdoptOpenJDK)"
)
public class PersonMapperImpl implements PersonMapper {
#Override
public Person toEntity(PersonRequest req) {
if ( req == null ) {
return null;
}
PersonBuilder person = Person.builder();
person.customName( req.getPersonName() );
return person.build();
}
}
So, I decided to guess like this about Annotation Processor(AP)'s process.
Reference link
this case is first Lombok, second MapStruct.
Lombok make getter/setter method with #Data
MapStruct can use access method. So, make mapper code by 'setter'
---------- Next round in AP---------
Lombok make builder method with #Builder
MapStruct don't be changed. Because, code already generated.
-> Finally, 'XXMapperImpl.java' use 'setter' method.
Next case is first MapStruct, second Lombok.
MapStruct try to generate, but there is nothing access method in Object class.
Lombok make getter/setter method with #Data.
---------- Next round in AP---------
Lombok make builder method with #Builder.
MapStruct pick up changes created by Lombok. So, MapStruct generate code by using builder.
-> Finally, 'XXMapperImpl.java' use 'builder' method.
Question)
Did I understand correctly?
Is Lombok getter/setter and builder creation divided into two rounds? First is getter/setter and next builder?

What is the class type of a #Builder object before calling build()?

I have done this before but forgot and couldn't find the answer easily online.
Let's say I have lombok on a POJO like
#Builder
#NoArgsConstructor
class Car {
private int gallons;
private int wheels;
private String name;
}
and I want to use the builder notation in some logic
public Car getCar(boolean isNew) {
<I dont know what type to put here> carBase = Car.builder().wheels(4);
if(!isNew) {
return carBase.gallons(10).build();
}
else {
return carBase.gallons(0).build();
}
}
What type should I use to fill in?
Okay, so I was actually running into this error Why is Lombok #Builder not compatible with this constructor? which was breaking my #Builder class.
Apparently lombok will generate a static nested class in the class annotated with #Builder called <classname>Builder, so to answer my original question there would be a valid class called Car.CarBuilder.

What is the difference of annotating #Builder on constructor or on class declaration? (Lombok)

What is the difference between these two usage of #Builder?
import lombok.*;
class BuilderAnnotationOnConstructor{
Integer fieldOne, fieldTwo;
#Builder
public BuilderAnnotationOnConstructor(int fieldOne, int fieldTwo) {
this.fieldOne = fieldOne;
this.fieldTwo = fieldTwo;
}
}
#Builder
class BuilderAnnotationOnClass{
Integer fieldOne, fieldTwo;
public BuilderAnnotationOnClass(int fieldOne, int fieldTwo) {
this.fieldOne = fieldOne;
this.fieldTwo = fieldTwo;
}
}
They both compile and run fine but I have noticed weird behaviors in the second case when the annotation is on the class declaration (e.g. in a large project of mine, attributes values assigned to wrong/swapped variable names; unfortunately I was not able to reproduce these behaviors in this simple example)
From Lombok doc :
*Now that the "method" mode is clear, putting a #Builder annotation on a constructor functions similarly; effectively, constructors are just static methods that have a special syntax to invoke them: Their 'return type' is the class they construct, and their type parameters are the same as the type parameters of the class itself
Finally, applying #Builder to a class is as if you added #AllArgsConstructor(access = AccessLevel.PACKAGE) to the class and applied the #Builder annotation to this all-args-constructor. This only works if you haven't written any explicit constructors yourself. If you do have an explicit constructor, put the #Builder annotation on the constructor instead of on the class. Note that if you put both #Value and #Builder on a class, the package-private constructor that #Builder wants to generate 'wins' and suppresses the constructor that #Value wants to make. *
from https://projectlombok.org/features/Builder

Mapstruct Invoking implicitly other mapper with multiple parameter

Given the following classes and a mapper that takes mulitple source arguments
(I use lombok to keep source as short as possible.)
#Getter
#Setter
public class MySourceOne {
private String src1;
}
#Getter
#Setter
public class MySourceTwo {
private String src2;
}
#Getter
#Setter
public class MyTargetObject {
private String prop1;
private String prop2;
}
#Mapper
public interface MyTargetObjectMapper {
#Mapping(target="prop1", source="a")
#Mapping(target="prop2", source="b")
public MyTargetObject mapMyObject(String a, String b);
}
#Getter
#Setter
public class MyComplexTargetObject {
private MyTargetObject myTargetObject;
}
I am trying to create a mapper for MyComplexTargetObject that will invoke implicitly the MyTargetObjectMapper .
But the "source" won't allow to map multiple parameter like this
#Mapper(uses= {MyTargetObjectMapper.class})
public interface MyComplexTargetObjectMapper {
#Mapping(target="myTargetObject", source="one.src1, two.src2")
public MyComplexTargetObject convert(MySourceOne one, MySourceTwo two);
}
So I am trying to use an expression="..." instead of source, but nothing works so far.
Any thoughts a clean way to do this without calling the MyTargetObjectMapper in a concrete method?
MapStruct does not support selection of methods with multiple sources.
However: you can do target nesting to do this.
#Mapper
public interface MyComplexTargetObjectMapper {
#Mapping(target="myTargetObject.prop1", source="one.src1" )
#Mapping(target="myTargetObject.prop2", source="two.src2")
public MyComplexTargetObject convert(MySourceOne one, MySourceTwo two);
}
And let MapStruct take care of generating the mapper. Note: you can still use a MyComplexTargetObjectMapper to do single source to target to achieve this.

How to override Lombok Setter methods

I'm using lombok in my project and generation Setters and Getters using #Setters and #Getters annotations on top of POJO class. I'm trying to override setters method of a property but it's not working
I want to check if JSON property is Empty or Null i want to set default value in Setter method
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
#Accessors(chain = true)
#ToString
public class DefaultModel {
private String name;
#Setter(AccessLevel.NONE)private String age;
public void setAge(String age) {
if(age==null||age.trim().isEmpty()||age.equals("null")) {
this.age="10";
}else {
this.age=age;
}
}
}
Working scenarios:
{
"name":"some",
"age":null
}
{
"name":"some",
"age":"null"
}
{
"name":"some",
"age":" "
}
Failed Scenario :
{
"name":"some"
}
Output:
DefaultModel(name=some, age=null)
And i'm following this as reference also here, but no luck so far
Either you just hit a bug I've never seen or you're testing it wrong.
An annotation like
#Setter(AccessLevel.NONE) private String age;
on the field level indeed stops the setter from being generated. But given that you're defining a setter, you don't even need it. An explicit #Setter stops the generation, too.
I've just tried your example using Eclipse 4.7.3a and Lombok 1.18.0 and your (buggy) setter gets called. I've been using Lombok a lot over a few years and never encountered such a bug.
Most probably the problem is that your JSON deserializer does not use setters at all. I guess, you're testing something like
DefaultModel defaultModel = deserialize("{\"name\":\"some\"}", DefaultModel.class);
instead of testing the setter directly. And that's the problem.
It possible that JSON deserializer uses constructor generated by Lombok (not setters).
Have a look here:
Jackson deserialize default values missing

Categories

Resources