I have the following JPA entity
@Data
@Builder
public class Post {
@Id
@GeneratedValue
UUID id;
@OneToMany
Set<PostTags> tags;
String content;
}
@Data
public class PostTag {
@Id
@GeneratedValue
UUID id;
@OneToOne
Post post;
String tag;
}
Using lombok @Builder I want to be able to do the following
Post post = Post.builder()
.tags("hello", "world")
.content("Hello world")
.build();
I am presuming I need a custom builder along the lines of
public static class PostBuilder {
private Set<String> myTags = new HashSet<>();
public PostBuilder tags(String... tags) {
myTags.addAll(Arrays.asList(tags));
return this;
}
}
From the documentation it appears there ObtainVia
annotation that I can use, but I am not sure how to get around it (no example on the doc) and especially since I only want myTags
to be a builder specific thing, and not be exposed on the main class itself.
ObtainVia
only works for toBuilder
, so that won't help much in this case.
I suggest the following approach.
First, add a factory method in PostTag
, eg createTag(String)
. This method only sets tag
in the instance it creates and leaves everything else null
. Statically import it into the class where you want to use PostBuilder
.
Next, use @Singular
on tags
. Then you can write:
Post post = Post.builder()
.tag(createTag("hello"))
.tag(createTag("world"))
.content("Hello world")
.build();
Finally, customize the build()
method so that it first creates the Post
instance (like an uncustomized build()
method would) and then sets this newly created Post
instance as post
in all PostTag
instances. Have a look at the delombok
ed code to make sure you use the right builder class and method headers when customizing the builder.
You can use @Accessors
for what you're asking:
Post
@Data
@Accessors(chain = true)
public class Post {
@Id
@GeneratedValue
private UUID id;
@OneToMany
private Set<PostTags> tags;
private String content;
public Post tags(String... tags) {
Arrays.stream(tags)
.map(tag -> PostTags.builder().tag(tag).build())
.forEach(this.tags::add);
return this;
}
}
PostTags
@Data
@Builder
public class PostTags {
@Id
@GeneratedValue
private UUID id;
@OneToOne
private Post post;
private String tag;
}
When you using @Accessors(chain = true)
, The setters will return this
reference instead of void
, and then your code will act this way:
Post post = new Post().setId(id).tags("aaa", "bbb");
If you want your code to be more similar to builder then add fluent
value to the annotation: @Accessors(chain = true, fluent = true)
It will remove the set<Something>
from the setters and just use the name of the fields, and then your code will look like this:
Post post = new Post().id(id).content("hello").tags("aaa", "bbb");
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.