What is the precedence of Lombok annotations? - java

I know that #EqualsAndHashCode have a precedence over #Data, but what about other annotations? Is there any simple rule that can be used to determine it?

I know just one rule: A more specific annotation takes precedence. As #Data doesn't allow to configure anything about the #EqualsAndHashCode computation details, the latter is clearly more specific. Similarly for #Data vs. #Getter and others.
Another case is class-level vs. field-level annotation, where the former can be overridden by the latter.
Note that doing it the other way round would make no sense at all.
There are some border cases like #Builder vs. #Data, where it's unclear what constructor should be generated (IIRC they require AllArgsConstructor and NoArgsContructor, respectively). Specifying the constructors explicitly helps.

Related

In Lombok, what is the difference between #AllArgsConstructor and #RequiredArgsConstructor?

Lombok offers a variety of annotations for java constructors, including but not limited to #AllArgsConstructor and #RequiredArgsConstructor. What is the difference between these two and when do you use one over the other? I found this documentation but the verbiage is a little convoluted and I'm having trouble following the basic differences between the two.
In short, use #AllArgsConstructor to generate a constructor for all of your class's fields and use #RequiredArgsConstructor to generate a constructor for all class's fields that are marked as final.
From the documentation,
#AllArgsConstructor generates a constructor with 1 parameter for each field in your class.
#RequiredArgsConstructor generates a constructor with 1 parameter for each field that requires special handling. All non-initialized final fields get a parameter, as well as any fields that are marked as #NonNull that aren't initialized where they are declared.

Autogenerating constructor properties with Lombok for Jackson to deserialize when multiple constructors exists

I have an immutable class defined as:
#Value
#RequiredArgsConstructor(access = AccessLevel.PRIVATE)
#AllArgsConstructor(access = AccessLevel.PRIVATE)
public class ImmutableDTO {
(...)
}
Being immutable, I would like to deserialize the JSON that represents through a constructor.
I would like to avoid having to explicitly mark the binding properties with either #ConstructorProperties or #PropertyNames.
1.So first of all I tried to look for a way to do this with Jackson alone, since in other cases, Jackson is smart enough. Adding ParameterNames module on pom.xml and defining the constructor
#AllArgsConstructor(access = AccessLevel.PRIVATE, onConstructor_= {#JsonCreator(mode = JsonCreator.Mode.PROPERTIES)})
seems futile, for the marking of each property seems to be needed either way.
2.Therefore I looked for a Lombok solution. My favourite approach would have been finding out an explicit annotation that marks a particular constructor for generating the Constructor Properties, but I could not find it
3.As a fallback I relied on the lombok.anyConstructor.addConstructorProperties = true global lombok.config setting, but then it annotates the properties for both of my constuctors, so I end up with an error: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Conflicting property-based creators:. I could not find a lombok facility to opt-out a particular constructor from the property marker generation (something like the legacy #RequiredArgsConstructor(suppressConstructorProperties = true))
So, is there any way to accomplish any of my approaches (by order of preference), or at least any at all?
P.S: I cannot use #JsonDeserialize(builder = (...)) facility either since my #Builder is precalculating some fields, i.e, using the alternative constructor (that's precisely why I need both, one is for Jackson and the other for manipulation by code (builder), which has calculated fields)
P.S2: I researched the boot option jackson.mapper.infer_creator_from_constructor_properties: true but either I am doing something wrong or it is just the explicit feature that otherwise gets autoregistrated when importing jackson-module-parameter-names in pom.xml

Inheritance with lombok annotation get errors

In my project, lombok is used to avoid writing getters and setters for a class.
I have two classes Child extends Parent:
#Value
#Builder
#AllArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class Parent {
#Nonnull
#JsonProperty("personId")
private final String personId;
#JsonProperty("personTag")
private final String personTag;
...
}
And
#Value
#Builder
#AllArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class Child extends Parent {
#Nonnull
#JsonProperty("childId")
private final String childId;
...
}
But this doesn't seems work as no default constructor available in Parent. I'm not familiar with the lombok annotation. Is there any good way to extend the Base class and use the lombok annotation at the same time?
TL;DR: add #NonFinal annotation to your superclass
Details: #Value annotation makes the class final, so you cannot inherit from it. Experimental #NonFinal annotation should prevent this.
import lombok.Value;
import lombok.experimental.NonFinal;
#Value
#NonFinal
public class Parent {
REF: https://projectlombok.org/features/Value
NOTE: For performance reasons (if it matters) final (value) objects can be (theoretically) super fast. The optimizer can allocate them in the stack memory, or reuse the same stack block in cycles, so no GC overheads.
(This is similar to how .NET structure value objects are usually allocated by .NET framework)
By adding #NonFinal such an optimization opportunity disappears.
Class hierarchies + lombok doesn't work particularly well, in the sense that the lombok operations done on your Child class don't know anything about parent.
However, your specific question seems answerable:
The Parent class has a constructor that takes all fields, because you asked lombok to make this constructor via #AllArgsConstructor. Therefore, it does not have a no-args constructor. If you want both constructors (the one that takes all fields + a second one that takes no arguments, a.k.a. the default constructor), also add a #NoArgsConstructor annotation to tell lombok that you want that.
NB: #Builder does not work with hierarchy either, but the fresh new #SuperBuilder feature does. I'm pretty sure you want to replace #Builder with #SuperBuilder here. SuperBuilder requires that ALL classes in the hierarchy are annotated with #SuperBuilder and not #Builder.

Add rules when creating a POJO

I'm using lombok's annotation #Data when writing pojos because it automatically generates constructor, hashCode as well as other methods for me. It worked like a charm until I was trying to use #Data in such a pojo class.
#Data
public class MyPojo {
private final String name;
private final int from;
private final int to;
// other fields
}
What I need to do is to restrict values of from and to when creating this pojo so that to will always be greater than from, but it seems that in order to achieve this logic, I have to rewrite the constructor all by myself with lots of code similar to this.name = name.
PS: I think using super from inheritance could be a workaround, but it may make the program harder to be understood.
Is there any better way to satisfy this need?
#Data annotation is not providing any way to validate construction arguments. I feel you need to annotate your pojo with #Getter #Setter #ToString #EqualsAndHashCode annotations and write constructor on your own.
Looking at Lombok's website, I don't see any way to restrict constructor parameters to specific values, especially relative to another variable that may have not been initialized yet. You'll probably have to create a concrete constructor for this class.
but it may make the program harder to be understood
I really wouldn't worry about that as you're already using Lombok, which would make any big program very confusing when trying to track down a specific field/method.

How do I prevent JAXB from binding superclass methods of the #XmlRootElement when marshalling?

I have a class that is annotated as the #XmlRootElement with #XmlAccessorType(XmlAccessType.NONE). The problem that I am having is that the superclass's methods are being bound, when I do not want them to be bound, and cannot update the class. I am hoping there is an annotation that I can put on the root element class to prevent this from happening.
Example:
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
public class Person extends NamedObject {
#XmlElement
public String getId() { ... }
}
I would expect that only the methods annotated #XmlElement on Person would be bound and marshalled, but the superclass's methods are all being bound, as well. The resulting XML then has too much information.
How do I prevent the superclass's methods from being bound without having to annotate the superclass, itself?
According to this StackOverflow post:
How can I ignore a superclass?
It is not possible with JAX-B to ignore the superclass without modifying the superclass.
Quoting the relevant portion of that post:
Update2: I found a thread on java.net
for a similar problem. That thread
resulted in an enhancement request,
which was marked as a duplicate of
another issue, which resulted in the
#XmlTransient annotation. The comments
on these bug reports lead me to
believe this is impossible in the
current spec.
Just add
#XmlAccessorType(XmlAccessType.NONE)
in front of EACH superclass declaration (and the class itself).
In your case:
#XmlAccessorType(XmlAccessType.NONE)
class NamedObject{
[ ... ]
}
Remember that this has to be done really for each superclass, it is often
forgotten when dealing with huge class dependency trees.
Interfaces, of course, don't need any JAXB annotations.
I know this question is quite old, but there is a kind of solution which works if your superclass is in the same package as its child.
Create a package-info.java in your package and insert
#XmlAccessorType(XmlAccessType.NONE)
package my.package.with.classes;
Obviously, it sets XmlAccessType.NONE upon all classes in the package. Myself, I use it in every package in our domain model. Therefore, I'm pretty safe. However, if your class is 'out of reach', f.e. it's in the JDK, use the solution from the accepted answer in [JAX-B] How can I ignore a superclass?.
I hope it's helpful for anynone who stumbles upon this question as I did.
I'm facing the exact same problem.
My superclass does not handle any JAXB annotations (it doesn't have to) and I would like my subclass not to include superclass properties while marshalling.
Adding the XmlAccesorType on superclass cannot be the solution as I have no way to modify the superclass.
Is there any other solution?
Replace your JAX-B implementation with MOXy and you can do anything you want. It has a ton of extensions that go above and beyond normal JAX-B, one of which will allow you to ignore inherited properties, etc. It also supports moving JAX-B annotations to an XML mapping file so you can keep multiple sets of mappings.
A solution I have found, but which might not work for you depending on what you want to do, is to override the getters you want to ignore and let them return null. The JAXB specs, and by extension the implementations, ignore fields that contain a null value. Note that if you still need to be able to access the superclass value itself using the subclass, you may need to add a secondary accessor method that is not a getter and adjust your code accordingly.

Categories