Using Jackson with Lombok's #Accessors(fluent=true) requires to add #JsonAutoDetect(Visibility.Any) annotation:
#Data
#NoArgsConstructor
#Accessors(fluent=true)
public class Pojo{
private String fieldOne;
private String fieldTwo;
}
I am curious of the performance of Visibilty.Any. Does it use reflection or compile time hooks are added?
Jackson uses reflection plus caching to implement serialisation and deserialisation processes anyway. Using this annotation does not add any noticeable performance cost. For more info, take a look how it is implemented: JsonAutoDetect.java. It allows you to change default visibility configuration for fields, getters, setters, creators and constructors.
Related
In sonar rules, there is a S00107 rule for "Methods should not have too many parameters". This rule has exceptions for some annotations:
Exceptions
Methods annotated with Spring's #RequestMapping (and
related shortcut annotations, like #GetRequest) or #JsonCreator may
have a lot of parameters, encapsulation being possible. Such methods
are therefore ignored.
Is it possible to add another annotations to this exceptions?
My case: I have constructors, annotated by the Lombok's #Builder, which contains a lot of parameters! So i want to ignore this rule on these constructors.
public class MyClass extends MySupperClass {
#Builder
public MyClass(String a, int b, ..., String z) {
}
}
Try to add #SuppressWarnings("squid:S00107")
Move #Builder to class level,
If you need super fields use lombok's #SuperBuilder in class level
The #SuperBuilder annotation produces complex builder APIs for your classes. In contrast to #Builder, #SuperBuilder also works with fields from superclasses
Intellij IDEA's lombok-plugin version 0.27 added support
Fixed #513: Add support for #SuperBuilder
Is there a way to customise the generated code for #Setter?
Consider the following simple class:
#Entity
#Getter
#Setter
#NoArgsConstructor
public class MyEntity implements Serializable {
#Id private long id;
#OneToMany
private Set<AttributeColumn> columns = new HashSet<>();
public void setColumns(Set<AttributeColumn> columns) {
this.columns.clear();
this.columns.addAll(columns);
}
}
I want Lombok to generate the Setter for columns as I implemented it in the example above. This should only be done on classes annotated with #Entity and on attributes that are a Collection. The Setter for other attributes, in this example id should be generated as usual.
Is there a way to customise the generation of the Setter code depending on those criteria?
No.
No, there's no such feature and no plans for it.
As already stated in a comment, you could do it yourself, but it's not easy at all. Moreover, you'd have to decide to either hardcode the logic (simple but probable unusable for others) or interpret something like
#SetterWhen(#Or(
#Condition(annotatedWith=Entity.class),
#Condition(declaredType=Collection.class)))
which is close to impossible to implement (as this information is unavailable when Lombok runs).
Currently, all you can do is to allow on suppress the generation on a per field basis. There's no possibility to generate a different setter, however
there's a related feature: #Singular, which may or may not help you.
I have a bunch of classes, which in turn contain many inner/nested classes, that need annotations for deserialization (#JsonIgnoreProperties) and for reducing Equals overriding boilerplate (#EqualsAndHashCode, Groovy default API, not Lombok).
My code looks like this:
#JsonIgnoreProperties(ignoreUnknown = true)
#EqualsAndHashCode(includeFields = true)
class SomeClass {
String id
#JsonIgnoreProperties(ignoreUnknown = true)
#EqualsAndHashCode(includeFields = true)
class InnerOne {
String foo
}
#JsonIgnoreProperties(ignoreUnknown = true)
#EqualsAndHashCode(includeFields = true)
class InnerTwo {
String bar
}
// and so on...
}
Both those annotations belong to third party libraries and are not marked as #Inherited, hence I'm forced to repeat them in each inner class.
Is there a way to reduce that boilerplate?
The author of the annotation processor has decided whether it is a good idea to inherit annotations or not.
The author might write the annotation processor to inherit annotations, so that the user has to write fewer annotations.
The author might write the annotation processor to not inherit annotations, so that the meaning of a class is obvious by looking at the class alone, without having to read every superclass as well.
Either of these is a defensible choice. I tend to lean toward the latter, because it improves readability, and code is read more often than it is written.
If you wish to change the behavior, you will need to modify the semantics of the annotation processor by modifying its source code. In your case, it is probably easier to write the extra annotations.
I have several different POJOs that use a builder pattern, but after adding a builder for each one and generating Object.toString, Object.hashCode and Object.equals, my classes end up being around 100 lines of code. There has to be a better way to handle this. I think having some sort of a reflective builder would help out a lot, but I'm not sure this would be good practice and I'm also not sure how I'd exactly make it happen. In other words, is there a way to implement a builder like this?
A simple POJO:
public class Foo {
public int id;
public String title;
public boolean change;
...
}
Then some sort of reflective builder:
Foo = ReflectiveBuilder.from(Foo.class).id(1).title("title").change(false).build();
Short answer no. What you ask for is not possible. Reflection looks at the code at runtime and invokes methods dynamically, it cannot generate actual methods.
What you could do would be:
Foo foo = ReflectiveBuilder.from(Foo.class).
set("id", 1).
set("title", "title").
build();
This has three massive problems:
the fields are Strings - a typo causes a runtime error rather than a compile time one,
the values are Objects - the wrong type causes a runtime error rather than a compile time one, and
it would be much slower than the alternative as Reflection is very slow.
So a reflection based solution, whilst possible (see Apache Commons BeanUtils BeanMap) is not at all practical.
Long answer, if you're willing to allow some compile time magic, you can use Project Lombok. The idea behind Lombok is to generate boilerplate code from annotations using the Java annotation preprocessor system.
The really magical thing is that all IDEs, well the big 3 at least, understand annotation preprocessing and code completion will still function correctly even though the code doesn't really exist.
In the case of a POJO with a Builder you can use #Data and #Builder
#Data
#Builder
public class Foo {
public int id;
public String title;
public boolean change;
...
}
The #Data annotation will generate:
a required arguments constructor (that takes all final fields),
equals and hashCode methods that use all fields (can be configured with the #EqualsAndHashCode annotation)
a toString method on all fields (can be configured with the #ToString annotation and
public getters and setters for all fields (can be configured using the #Getter / #Setter annotations on fields).
The #Builder annotation will generate an inner class called Builder that can be instantiated using Foo.builder().
Do make sure you configure the equals, hashCode and toString methods as if you have two classes with Lombok that have references to each other then you will end up with an infinite loop in the default case as both classes include the other in these methods.
There is also a new configuration system that allows you to use, for example, fluent setters so you can more of less do away with the builder if your POJO is mutable:
new Foo().setId(3).setTitle("title)...
For another approach you can look at Aspect-oriented programming (AOP) and AspectJ. AOP allows you do chop your classes up into "aspects" and then stick them together using certain rules using a pre-compiler. For example you could implement exactly what Lombok does, using custom annotations and an aspect. This is a fairly advanced topic however, and might well be overkill.
Maybe Project Lombok (yes the website is ugly) is an option for you. Lombok injects code into your classes based on annotations.
With Lombok you use the #Data annotations to generated getters, setters, toString(), hashCode() and equals():
#Data
public class Foo {
public int id;
public String title;
public boolean change;
}
Have a look at the example on the #Data documentation section to see the generated code.
Lombok also provides a #Builder that generates a builder for your class. But be aware that this is an experimental feature:
#Builder
public class Foo {
public int id;
public String title;
public boolean change;
}
Now you can do:
Foo foo = Foo.builder()
.id(123)
.title("some title")
.change(true)
.build();
I personally use this website to create all the boilerplate code for the POJOs for me. All you need to do is to paste the JSON that you want to parse, and it will generate all the classes for you. Then I just use Retrofit to do the requests/caching/parsing of the information. Here is an example of Retrofit and POJOs in my Github account.
I hope it helps!
I created a small library CakeMold to do fluent initialization of POJOs. It uses reflection, what is certainly not fast. But can be very helpful when need to write tests.
Person person = CakeMold.of(Person.class)
.set("firstName", "Bob")
.set("lastName", "SquarePants")
.set("email", "sponge.bob#bikinibottom.io")
.set("age", 22)
.cook();
I want to use a data class in Lombok. Since it has about a dozen fields, I annotated it with #Data in order to generate all the setters and getter. However there is one special field for which I don't want to the accessors to be implemented.
How does Lombok omit this field?
You can pass an access level to the #Getter and #Setter annotations. This is useful to make getters or setters protected or private. It can also be used to override the default.
With #Data, you have public access to the accessors by default. You can now use the special access level NONE to completely omit the accessor, like this:
#Getter(AccessLevel.NONE)
#Setter(AccessLevel.NONE)
private int mySecret;
According to #Data description you can use:
All generated getters and setters will be public. To override the
access level, annotate the field or class with an explicit #Setter
and/or #Getter annotation. You can also use this annotation (by
combining it with AccessLevel.NONE) to suppress generating a getter
and/or setter altogether.