Mapstruct Invoking implicitly other mapper with multiple parameter - java

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.

Related

Remove prefix of variable in generating lombok getter/setter

I have some code like this:
#Getter
#Setter
public class CreditContract {
private Long _id;
private String _customerId;
}
from which Lombok will generate these setter/getter:
public void set_id(Long id) {...}
public Long get_id() {...}
How can I control that the underscores are removed? Because I need it like that:
public void setId(Long id) {...}
public Long getId() {...}
I've found that there is one configuration lombok.accessors.prefix=_ but I want to control this directly in the class, probably direct in the annotation or with an additional annotation. In other words, I don't want to have a lombok.config file.
I couldn't find any information at StackOverflow.
I do believe #Accessors annotation will help
Found this solution, too, as Andrey pointed out (https://projectlombok.org/features/experimental/Accessors):
#Getter
#Setter
#Accessors(prefix = {"_"})
public class CreditContract {
}
This will remove the prefix _ from my variables when they are used in naming the getter/setter. This can be even used for different prefixes:
#Getter
#Setter
#Accessors(prefix = {"_", "val})
public class CreditContract {
...
private String valTest;
}
Will generate
public String getTest(){..}
public void setTest(String string){..}

Assign custom lombok builder method as singular handler

I have the following table class which makes usage of #Builder Lombok annotation with a custom builder class:
#Builder
public class MyTable {
...
public static class MyTableBuilder {
public void entry(final MyEntry myEntry) {
...
}
}
}
In another class that is composed by MyTable I would like to make usage of #Builder + #Singular annotations so that I can build TableOwner instances specifying entry by entry.
#Builder
public class TableOwner {
#Singular("entry")
private final MyTable entries;
}
TableOwner.builder()
.entry(...)
.entry(...)
.entry(...)
.build()
However the #Singular annotation on entries results the error "Lombok does not know how to create the singular-form builder methods for type 'MyTable'; they won't be generated.".
Is there a way I can point to MyTableBuilder#entry method as the singular handler for entries?

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.

Changing one dto to another

#Getter
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class GenerateDaByContextDto {
private String cNumber;
private BusinessContext businessContext;
private String zCode;
private String yCode;
private String xCode;
private String event;
public GenerateContentDto toGenerateContentDto() {
return GenerateContentDto.builder()
.businessContext(businessContext)
.event(event)
.build();
}
}
I was making code review, when i wondered is it fine to change DTO's like that?
The need was that some methods have GenerateContentDto as param and it could be acquired from GenerateDaByContextDto DTO in the code.
Is there another option to make it better? Is it good regarding SRP rule?
I have simplified the DTOs fields.
Strongly speaking, it's opinion based and depends on project.
But let's remember single responsibility principle. DTO's responsible for data holding between layers, not for conversion. I prefer to have a simple converter with method like:
public class GenerateDaByContextDtoConverter {
public GenerateContentDto convert(GenerateDaByContextDto source) {...}
}
By the same reason, usually DTOs are immutable. You could use lombok's #Value annotation.
The one more solution may be composition, if it consistent with the business logic :
class GenerateDaByContextDto {
private GenerateContentDto generateContentDto;
...
}
You can replace #Getter ,#Builder,#AllArgsConstructor,#NoArgsConstructor with #Data
this is the better way to do it
#Data
public class GenerateDaByContextDto {
private String cNumber;
private BusinessContext businessContext;
private String zCode;
private String yCode;
private String xCode;
private String event;
/*
public GenerateContentDto toGenerateContentDto() {
return GenerateContentDto.builder()
.businessContext(businessContext)
.event(event)
.build();
}
*/
}

Spring Data Mongodb Convert Document Falsely

I have a document structure which has some generic class. For writing to mongodb everything is fine. But when reading documents from mongodb spring data converts document into object falsely. It converts a subdocument with another type. Both types (actual subcollection type and falsely converted type) are inherit from same abstract class.
Model Classes:(getter setters are generated by lombok )
#Data
public abstract class CandidateInfo {
private String _id;
}
#Data
public class CandidateInfoContainer<E extends CandidateInfo> {
private String _id;
private int commentCount = 0;
#Valid
private List<E> values = new ArrayList<>();
}
#Data
public class Responsibility extends CandidateInfo {
#NotNull
private String responsibilityId;
#ReadOnlyProperty
private String responsibilityText;
}
#Data
public class Experience extends CandidateInfo {
#Valid
private CandidateInfoContainer<Responsibility> responsibilities;
}
#Document
#JsonInclude(JsonInclude.Include.NON_NULL)
#Data
public class Candidate {
private String _id;
#Valid
private CandidateInfoContainer<Experience> experiences;
}
And if you create a mongoRepository like below:
#Repository
public interface CandidateRepository extends MongoRepository<Candidate,String>{
}
And use it like:
#Autowired
private CandidateRepository candidateRepository;
Candidate candidate = candidateRepository.findOne("documentId");
Then spring data mongo mapping converter creates candidates.experiences.responsibilities.values list as Experince list but it should be Responsibility list.
You can find a demo project in this link and more information about the issue. Can anyone point out what is wrong? Otherwise i have to write my own converter(demo has one)
If there is any unclear thing, you can ask.
Thanks.
I open an issue in spring-data-mongo here. Appareantly I caught a bug! Thanks everyone

Categories

Resources