I am struggling to map a string object from source(Relation.class) and to a List of target(RelationListDTO.class) .
Relation.java
public class Relation {
private String name;
private String email;
private String completeAddress;
// getters and setters
}
RelationListDTO.java
public class RelationListDTO {
private String name;
private String email;
private List<Address> address;
// getters and setters
}
Address.java
public class Address{
private String street;
private String city;
// getters and setters
}
Mapper class
#Mapper
public interface RelationMapper {
#Mapping(source = "completeAddress", target = "address.get(0).city")
RelationListDTO relationToListDto(Relation relation);
}
But it is not working. Could anyone please help.
What you are trying to do using MapStruct is not possible. Because MapStruct doesn't work with run time objects. MapStruct only generated plain java code for mapping two beans. And I find your requirement is little unique. You have a list of Addresses but want to map only city from source object? You can still do like this
#Mapping( target = "address", source = "completeAddress")
RelationListDTO relationToListDto(Relation relation);
// MapStruct will know to use this method to map between a `String` and `List<Address>`
default List<Address> mapAddress(String relation){
//create new arraylist
// create new AddressObject and set completeAddress to address.city
// add that to list and return list
}
Not sure if this was possible at the time of the accepted answer but I had the same problem as you and ended up doing it this way.
#Mapper(imports = Collections.class)
public interface RelationMapper {
#Mapping(expression = "java(Collections.singletonList(relation.getCompleteAddress()))", target = "address")
RelationListDTO relationToListDto(Relation relation);
}
Related
How can I define following mapping using Mapstruct java bean mapping. The problem how do I map the List ( with just one element) in source class to TargetPhone class
Source classes
class Source{
private String name;
private int age;
**This list always contain one element
and I cannot change this behavior or structure of this class**
private List<Phone> phones;
}
class Phone{
private Long id;
private String phoneNumber;
private String phoneColor;
// getters and setters
}
Target classes
class Target{
private String myName; **-->should map to Source.name**
private int myAge; **-->should map to Source.age**
private TargetPhone targetPhone;
// getters and setters
}
class TargetPhone{
private Long myId; **-->should map to Source.phones[0].id**
private String myPhoneNumber; **-->should map to Source.phones[0].phoneNumber**
private String myPhoneColor; **-->should map to Source.phones[0].phoneColor**
// getters and setters
}
Your mapper should be defined as shown below.
#Mapper
public interface MyMapper {
#Mapping(source="name", target="myName")
#Mapping(source="age", target="myAge")
#Mapping(source="phones", target="targetPhone")
Target sourceToTarget(Source source);
#Mapping(source = "id", target = "myId")
#Mapping(source = "phoneNumber", target = "myPhoneNumber")
#Mapping(source="phoneColor", target="myPhoneColor")
TargetPhone phoneToTargetPhone(Phone phone);
default TargetPhone listPhonesToTargetPhone(List<Phone> phones){
return phoneToTargetPhone(phones.get(0));
}
}
Where the default method does the magic of mapping the first element of Phone list to TargetPhone.
I am facing issue when I am trying to use ModelMapper to convert nested java objects into nested DTO's. Getting null for child dto's in parent dto object. Following are the code snippets.
Entity Classes :
public class User {
private String name;
private Address address;
private Product product;
}
public class Address {
private String area;
private String city;
}
public class Product {
private Integer productId;
private String productName;
private Double productPrice;
}
DTO's Classes :
public class UserDTO {
private String name;
private AddressDTO address;
private ProductDTO product;
}
public class AddressDTO {
private String area;
private String city;
}
public class ProductDTO {
private Integer productId;
private String productName;
private Double productPrice;
}
here is the mapper code :
ModelMapper mapper = new ModelMapper();
mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.LOOSE);
UserDTO userDTO = mapper.map(user, UserDTO.class);
System.out.println("Output User DTO : " + userDTO );
Output :
Output User DTO : UserDTO [name=xyz, address=null, product=null]
Here I want to convert User entity into UserDTO dto.
I am getting null values for address and product DTO's. What exactly I am missing here ? Does anyone have any idea ?
Note : I have added getters, Setters and toString() methods in entity and DTO's.
Here I found solution for nested DTO to Entity and vice versa conversions, I was missing some ModelMapper configurations that I have added below.
mapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(AccessLevel.PRIVATE)
.setMatchingStrategy(MatchingStrategies.STANDARD);
I have following DTOs:
#Data
public class PersonDTO implements Diffable<PersonDTO> {
private String id;
private String firstName;
private String lastName;
private List<AddressDTO> addresses;
#Override
public DiffResult diff(PersonDTO personDTO) {
return new DiffBuilder(this, personDTO, SHORT_PREFIX_STYLE)
.append("id", this.id, personDTO.getId())
.append("firstName", this.firstName, personDTO.getFirstName())
.append("lastName", this.lastName, personDTO.getLastName())
.append("addresses", addresses, personDTO.getAddresses())
.build();
}
}
#Data
public class AddressDTO implements Diffable<AddressDTO> {
private String id;
private String personId;
private String addressType;
private String street;
private String houseNumber;
private String postalCode;
private String city;
private String countryId;
#Override
public DiffResult diff(AddressDTO addressDTO) {
return new DiffBuilder(this, addressDTO, SHORT_PREFIX_STYLE)
.append("id", this.id, addressDTO.getId())
.append("personId", this.personId, addressDTO.getPersonId())
.append("addressType", this.addressType, addressDTO.getAddressType())
.append("street", this.street, addressDTO.getStreet())
.append("houseNumber", this.houseNumber, addressDTO.getHouseNumber())
.append("postalCode", this.postalCode, addressDTO.getPostalCode())
.append("city", this.city, addressDTO.getCity())
.append("countryId", this.countryId, addressDTO.getCountryId())
.build();
}
}
My main goal is to find differences between two similar person objects. Currently I've tried to use Diffable interface from apache commons which is perfectly good for object. Please advise how to deal with collections when size of each collection can be different. For instance few addresses were removed, few was added and few was updated. Please see example below:
Probably there is another library which helps to achieve similar goals, please advice
source can be your first object
target can be your second object
Iterator targetIt = target.iterator();
for (Object obj:source)
if (!obj.equals(targetIt.next())
// Element has changed
Many times I'm faced with a class which constructor method must contain list of arguments that is identical with the list of class instance variables.
As you see in the example there is "SOME" code to make this hapend.
I'm wondering how can I make this process less painful?
Example:
public class VimeoUser extends Schema {
#Getter #Setter private String uri;
#Getter #Setter private String name;
#Getter #Setter private String link;
#Getter #Setter private String location;
#Getter #Setter private String bio;
#Getter #Setter private String createdTime;
#Getter #Setter private String account;
#Getter #Setter private Map<String,Integer> statistics = new HashMap<>();
#Getter #Setter private List<Website> websites = new ArrayList<>();
#Getter #Setter private List<Portrait> portraits = new ArrayList<>();
public VimeoUser(
String uri,
String name,
String link,
String location,
String bio,
String createdTime,
String account,
Map<String,Integer> statistics,
List<Website> websites,
List<Portrait> portraits){
this.uri = uri;
this.name = name;
this.link = link;
this.location = location;
this.bio = bio;
this.createdTime = createdTime;
this.account = account;
this.statistics = statistics;
this.websites = websites;
this.portraits = portraits;
}
}
It is possible to use a pattern named Builder. It is explained in this question
Basically it works as following:
Create an inner static class Builder
Create a private constructor that take as an argument an object of type Builder
In the Builder class add methods that set a single value and returns this (current reference to instance of the Builder class)
In the body of the constructor of your class use the values passed in the Builder to set each property
add a method build in the Builder that calls the private constructor of your class
Here is an example:
public class NutritionalFacts {
private int sodium;
private int fat;
private int carbo;
public class Builder {
private int sodium;
private int fat;
private int carbo;
public Builder(int s) {
this.sodium = s;
}
public Builder fat(int f) {
this.fat = f;
return this;
}
public Builder carbo(int c) {
this.carbo = c;
return this;
}
public NutritionalFacts build() {
return new NutritionalFacts(this);
}
}
private NutritionalFacts(Builder b) {
this.sodium = b.sodium;
this.fat = b.fat;
this.carbo = b.carbo;
}
}
and to use it do the following:
NutritionalFacts nutritionalFacts = new NutritionalFacts.Builder()
.fat(200).carbo(50).build();
Using this pattern instead of pojo with setter and getter is useful because it is possible to use it also to build immutable objects (objects with all final fields). An immutable object is useful if you need to share it on a multithreaded environment because it is not necessary to synchronize the access to it.
Additionally it is possible to add some controls in the build method to be sure that all fields are setted as expected.
I guess writing pojos for database modelling does not necessarily needs constructor other than default no-arg constructor. If anyway required in some situations, Getters and setters can be used.
Builder pattern
If you want create a object with more readable way, you can use a simple builder pattern. Lombok support this such as #Getter or #Setter. You just add #Builder annotation and everything should works fine.
#Getter
#Builder
public class SomeClass {
private final String valueOne;
private final String valueTwo;
}
And then you can create object in this way.
SomeClass someClass = SomeClass.builder()
.valueOne("one")
.valueTwo("two")
.build();
Fluent accessors method
Alternative way to create a class is using #Accessors annotation with fluent = true. Then you can create a empty object and set the value what you needed in simple way.
#Getter
#Setter
#Accessors(fluent = true)
public class SomeClass {
private String valueOne;
private String valueTwo;
}
Simple sample using this way.
SomeClass someClass = new SomeClass()
.valueOne("one")
.valueTwo("two");
I see you are already using Lombok. There is a #AllArgsConstructor class-level annotation that will generate the constructor for you. If you want the default constructor, too, use #NoArgsConstructor additionally.
More info on the constructor-generating annotations here.
As per the requirement, I have parsed an XML file and set data into these two DTO classes:
public class DetailsDTO implements java.io.Serializable {
private String userid;
private String accountnum;
private Customer customer;
// setters and getters
public class Customer implements Serializable
{
private String street;
private String country;
// setters and getters
After adding data of the Customer class to DetailsDTO, I added this DetailsDTO to an ArrayList as shown:
List list = new ArrayList();
// and added these DetailsDTO class to an ArrayList
list.add(detailsDTO)
Now there is a Master DTO called as WholeDetails which consists of all variables defined in various DTO classes as shown.
class WholeDetails
{
private String userid;
private String accountnum;
private String street;
private String country;
}
Now, as you see, all the data is aviable within the ArrayList.
How can I extract the contents from ArrayList and map it to the WholeDetails?
You will have to do the mapping e.g.
List<DetailsDTO> list = new ArrayList<DetailsDTO>();
// and added these DetailsDTO class to an ArrayList
list.add(detailsDTO);
List<WholeDetails> wholeDTOList = new ArrayList<WholeDetails>();
for(DetailsDTO dto:list){
WholeDetails whole = new WholeDetails();
whole.setUserid(dto.getUserid());
whole.setAccountNum(dto.getAccountNum());
whole.setStreet(dto.getCustomer().getStreet());
whole.setCountry(dto.getCustomer().getCountry());
wholeDTOList.add(whole);
}
If you like it to be more short you could create an adapter class that maps the DetailsDTO to the WholeDetailsDTO and add the result object to the list