In one of my projects, I'm handling some POJOs that may have 20+ fields. I'm using the Builder Pattern to make object creation less cumbersome. Lombok's #Builder annotation really removes a lot of boilerplate code and speeds up my process. Thing is that I want to add Javadoc to the 'setter'-like methods in the various builders of my project. I've tried to put the Javadoc to the fields just like Lombok's recommendation on #Getter/#Setter but it doesn't seem to work. Is there any possible method to achieve what I want?
You can also use #Accessors(chain = true) instead of #Builder.
Your Getter and Setter will return your instance and you can also use Method-Chaining like in Builder Pattern.
The syntax will be like
Model model = new Model().setId(23L).setTitle("test");
We always use this instead of #Builder.
Lomboks recommendation should work with this solution
Related
Background
We are currently implementing an application using hexagonal architecture. Our REST API DTOs are mapped to our entities via MapStruct. This works fine. (Though, it would be much nicer if MapStruct would have support for hierarchical structures.)
Problem
However, we are facing a problem which is best described by the following example:
Consider you have an entity Person that stores the date of birth. Now, this
entity has a method which might be called int calculateAge().
The REST API's PersonDto will get an attribute int age.
Now, we want MapStruct to generate this mapping for us. Our approach was to try to configure #Mapping(target = "age", ...) to use the int calculateAge() method as source, but we did not succeed.
Believing this might be a straightforward application of MapStruct, we were quite disappointed to not come up with a clean solution after searching on this topic for hours.
Solutions
We found two solution approaches that work, but are (in our opinion) not really maintainable:
Use #Mapping(expression = "java(...)")
Use #AfterMapping to post process the constructed DTO and implement the required mappings in the annotated method
Question
Is there a cleaner way to achieve our goal, something which might look like this #Mapping(sourceMethod = "calculateAge", target = "age)?
Is there a cleaner way to achieve our goal, something which might look like this...
No, there isn't as of the MapStruct latest stable version (1.4.1.Final) of time of writing this answer. You have basically two choices which heavily depends what exactly and how you want to map the fields. I describe shortly in what case each solution is suitable for:
The first solution using expression introduces the problem the methods are hardcoded in the annotation. I prefer this solution only in the case of simple format conversions or calculations without calling a custom method (only from the existing Java API). Anyway, even with your proposed solution it would be still hardcoded. The syntax is the only thing that changes. There is effectively no difference in terms of maintainability:
#Mapping(target = "age", expression = "java(...)") // current API
#Mapping(sourceMethod = "calculateAge", target = "age") // hypothetical
Feel free to request for such feature. This solution in any case also requires imports within the mapper (#Mapper(imports = Another.class)) as well as the "hypothetical" one.
The annotation #AfterMapping is useful in case of more complex transformations and calculations. It's not as clean as a single annotation call and in fact you still write the mapping manually, however, it brings more control over the called methods which the IDE highlights before the compilation (at least you don't need an additional IDE-specific plugin). I'd go for this solution in case I need to call my custom methods and logics.
From what I've seen, Mapstruct relies on standard getters and setters. If you want to use a specific method then Mapstruct does work with #qualifiers, but I don't think the method can be in the entity. From my experience the best solution is to use #AfterMapping, as you mentioned.
Presently I am using swagger codegen tool to convert a RAML definition into swagger format and generating java client from this format. This gives me POJOs for all the data types mentioned in the RAML. Every time I change some data field in the RAML types, I have to regenerate the POJOs and all the code implementation in service layers has to be rewritten. It is becoming very cumbersome to repeatedly do the same things.
I am thinking if only these POJOs were generated with builder pattern, like,
mydataobject.builder.addfield1(10).addfield2(2);
it will greatly help me keep the code in service layer untouched.
Is there a way to auto-generate pojos that have builder methods in them?
You can use Lombok for that.
#lombok.Builder// Builder companion class, and static method
#lombok.Value // Getters, setters, and contructors
class Pojo {
String value;
Number number;
}
Which gives you this code:
final Pojo pojo = Pojo.builder()
.value("foo")
.number(100)
.build();
You have to proceed your generated code in order to add this annotations, see Add lombok (or any) annotation to swagger generated class for discussion of that.
I would like Lombok's toString() output to put each value on its own line. Enabling it like this would be great:
#ToString(includeNewLines = true)
public class MyClass {
...
}
Anything like that possible?
There is currently no direct #ToString annotation support for output formatting as described in your question. In fact, the Lombok #ToString documentationref includes the following disclaimer:
We don't promise to keep the output of the generated toString() methods the same between lombok versions. You should never design your API so that other code is forced to parse your toString() output anyway!
You could use: #ToString(onlyExplicitlyIncluded = true) to suppress normal toString field processing along with #ToString.Include to call an instance (non-static) method that takes no arguments to implement custom formatting, but that pretty much defeats the whole purpose.
If custom toString output formatting is important to you, a better option is available in the Apache Commons Langref org.apache.commons.lang3.builder package, which provides output format control using the ToStringBuilderapi and ToStringStyleapi classes.
I am working on a project that has a fair amount of data objects that use a "fluent interface" or "method chaining" on their setters so all of the setters in each data object return this. I have looked around and found this question, but it is unclear to me whether this can be used with Yaml as the annotations specifically mention JSON, and also this seems to enable mapping to objects using an actual builder pattern, which is a little different. The project is currently using SnakeYaml, but that can be tossed away if some other lib like Jackson can do this.
It turns out that this is in fact possible. Jackson supports yaml and will work with builder style setters by default without any extra configuration.
I'm using Oval to do validations, so we have code that looks like this:
#NotNull(errorCode = "NumberInvalid")
#NotNegative(errorCode = "NumberInvalid")
#Range(errorCode = "NumberInvalid", min=1, max=10)
protected Integer dollarAmount;
I want to be able to update the range dynamically if needed, say if we have a config file that changes every month or so, I want to be able to reflect those changes in the validation.
Is there a way I can do this with reflection so that I don't have to subclass every annotation in Oval?
As far as I'm aware this is not possible. Assuming your annotation retention is set to RUNTIME (which it would have to be for the validation to work) then what you will effectively have is a proxy class that implements the annotation interface, you won't be able to amend the values through reflection.
Though annotations looks cleaner with static codes :) but ...there is a way.. Did you tried using reflection ? can you post the approach . You can have a look at this
The purpose of reflection is to access class members (including setting fields), but it does not cover adding new members or modifying existing declarations. What you want is more similar to bytecode editing or code refactoring.