Given the Source class as defined below:
class Source{
private String name;
private int age;
private List<Phone> phones;
// getters and setters
}
and the Phone class as defined below:
class Phone{
private Long id;
private String phoneNumber;
// getters and setters
}
and the Target class as defined below:
class Target{
private String name;
private int age;
private List<Long> idsPhones;
// getters and setters
}
I have an interface is:
#Mapper
interface MyMapper{
Target toTarget(Source source);
Source toSource(Target target);
}
How can I map the List of Phones from the Source class to a List of idsPhones in the Target Class and vice versa?
In order to achieve this you need to help MapStruct a bit by telling how to map from Phone into Long. And the reverse as well.
Your mapper needs to look something like:
#Mapper(uses = PhoneRepository.class)
interface MyMapper {
#Mapping(target = "idsPhones", source = "phones")
Target toTarget(Source source);
#InheritInverseMapping
Source toSource(Target target);
default Long fromPhone(Phone phone) {
return phone.getId();
}
}
If your PhoneRepository contains a method that accepts a Long and returns Phone then MapStruct will automatically know what to do and invoke that method.
Related
Need some help here! I have a Java Rest API which is getting data from a .net endpoint and passing it on to the UI. The JSON properties are in capital case and I want to convert them in JAVA before sending it to the UI. Any pointers on this?
In java, I have a class like below:
public class Person {
#JsonProperty("Name")
private String name;
#JsonProperty("Age")
private int age;
}
I am using #JsonProperty as keys in .net are starting with capitalCase. How can I convert this back before sending it to the UI in Java?
Thanks for the help!
Create another class with the same structure and use there other names that you want. Something like this:
// Class to read .NET object
public class Person {
#JsonProperty("Name")
private String name;
#JsonProperty("Age")
private int age;
}
// Class to represent the object in Java REST API
public class Person {
#JsonProperty("name")
private String name;
#JsonProperty("age")
private int age;
}
// Class to represent the object in Java REST API,
// in case you use some standard library that
// uses property names for JSON as is
public class Person {
private String name;
private int age;
}
Of course you should put these classes into different packages.
Your code can look as follows:
xxx.dotnet.Person dotnetPerson = doSomethingViaDotNet(...);
yyy.rest.Person restPerson = new yyy.rest.Person();
restPerson.setName(dotnetPerson.getName());
restPerson.setAge(dotnetPerson.getAge());
...
return restPerson;
If you decide to use MapStruct, your code may looks as follows:
#Mapper
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper( PersonMapper.class );
yyy.rest.Person dotnetToRest(xxx.dotnet.Person dotnetPerson);
}
Since all attributes have the same names and types you don't need anything else in your mapper.
MapStruct will generate a class that implements this interface. Usage will be as follows:
restPerson = PersonMapper.INSTANCE.dotnetToRest(dotnetPerson);
I have entity class
public Class StudentEntity{
private int id;
private String name;
private AddressEntity address;
private ProfileEntity profile;
//getter setter
}
public Class StudentDTO{
private int id;
private String name;
private AddressDTO address;
private ProfileDTO profile;
//getter setter
}
when I use BeanUtils.copyProperties(); (from spring/apache common) it copies the id and name alone. How to copy the address and profile also?
If custom util has to be written, could you please share the snippet?
BeanUtils, cloning OR serialization would not work here as the inner data types are different. I would suggest you to set the fields of StudentDTO manually. You could use conversion constructor for AddressDTO and ProfileDTO. Copy constructor is the legal name, but since we are converting type also, better name would be a conversion constructor instead.
An example of conversion constructor in JDK is ArrayList(Collection<? extends E> c) , i.e. https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html#ArrayList-java.util.Collection- which generates an ArrayList from any Collection object and copy all items from Collection object to newly created ArrayList object.
Example:
StudentEntity studentEntityObj = new StudentEntity();
studentEntityObj.setId(1);
studentEntityObj.setName("myStudent");
AddressEntity addressEntityObj = new AddressEntity();
addressEntityObj.setCity("myCity");
studentEntityObj.setAddress(addressEntityObj);
// All above lines would be taken care of already (i.e. data is filled from DB)
StudentDTO studentDTOObj = new StudentDTO();
// Call conversion constructor
AddressDTO addressDtoObj = new AddressDTO(addressEntityObj);
studentDTOObj.setAddress(addressDtoObj);
studentDTOObj.setId(studentEntityObj.getId());
studentDTOObj.setName(studentEntityObj.getName());
System.out.println(studentDTOObj.toString());
where AddressDTO (OR ProfileDTO for that matter) including a conversion constructor looks like:
public class AddressDTO {
private String city;
// Conversion constructor
public AddressDTO(AddressEntity a) {
this.city = a.getCity();
}
#Override
public String toString() {
return "AddressDTO [city=" + getCity() + "]";
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
prints
StudentDTO [id=1, name=myStudent, address=AddressDTO [city=myCity]]
You can try to use SerializationUtils.clone(). This method deep clone your object. But you should mark your objects as Serializable.
https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/SerializationUtils.html#clone(T)
I have a Base dto and a dto which extends it
public abstract class AbstractItem {
private String upc;
private String quantity;
//getter and setter for upc and quantity
}
public class OrderedItem extends AbstractItem {
private String orderId;
// getter and setter for orderId
}
Then I have a modal which I want to convert from OrderedItem. This modal extends a base modal
public abstract class AbstractModal {
private String qty;
public void setQty(String qty) {
this.qty = qty;
}
public String getQty() {
return qty;
}
}
public class ItemModal extends AbstractModal {
private String orderNbr;
private String upcNbr;
// getter and setter for orderNbr and upcNbr;
}
this is my mapper function using Mapstruct
#Mapper
public interface DtoMapper {
#Mappings({
#Mapping(source = "orderedItem.orderId" target = "orderNbr"),
#Mapping(source = "orderedItem.upc" target = "upcNbr"),
#Mapping(source = "orderedItem.quantity" target = "qty")
})
ItemModal convert(OrderedItem orderedItem);
}
During compilation I get an error Unknown property "qty" in result type test.modal.ItemModal.
Does Mapstruct support mapping fields of base class?
If yes, can you please tell me what is wrong with my code?
I am using java 8 and mapstruct 1.2.0
Edit: added getter and setter for qty in AbstractModal
I am using an implementation of an interface in Java.
For eg: There can be many PaymentTypes like Credit Card, Mobile etc.
I am making a REST API which contains an interface- how do I map this in JAXB, currently it gives me JAXBException occurred : 2 counts of IllegalAnnotationExceptions.
Currently I am using Apache-CXF and JAXb
#XmlRootElement
public class Payment {
#XmlElement
private PaymentType paymentType;
#XmlElement
private long price;
public Payment() {
}
public Payment(final PaymentType paymentType, final long price) {
super();
this.paymentType = paymentType;
this.price = price;
}
}
#Path("/trial")
public class TrialService {
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Payment> getPayments() {
final List<Payment> payments = new LinkedList<Payment>();
final CreditCardDetails creditCard = new CreditCardDetails(
"8767798778", "123", 12, 2016);
final Payment payment = new Payment(creditCard, 10);
payments.add(payment);
return payments;
}
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public PaymentDetails startPayment(final PaymentDetails paymentDetails) {
return paymentDetails;
}
}
public class CreditCardDetails implements PaymentType {
#XmlElement
private String creditCardNumber;
#XmlElement
private String cvv;
#XmlElement
private int expirationMonth;
#XmlElement
private int expirationYear;
public CreditCardDetails() {
}
#SuppressWarnings("javadoc")
public CreditCardDetails(
// final BillingAddress billingAddress,
final String creditCardNumber, final String cvv,
final int expirationMonth, final int expirationYear) {
super();
this.creditCardNumber = creditCardNumber;
this.cvv = cvv;
setExpirationMonth(expirationMonth);
setExpirationYear(expirationYear);
}
}
How should I be mapping this or should I be using an entirely different approach?
Edits:
For the POST method I am receiving a payment. Payment could contain any object CreditCard, Wallet etc. What annotation should I provide so that it is desirialized correctly.
Currently it throws a JAXB exception.
The full error message which you've got is:
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions PaymentType is an interface, and JAXB can't handle interfaces.
You need to use concreate class for your elements or point it in type attribute of #XmlElement annotation:
#XmlElement(type = CreditCardDetails.class)
private PaymentType paymentType;
If you have more classes that uses PaymentType interface then you may use the following solution:
#XmlAnyElement
#XmlElementRefs({
#XmlElementRef(type=CreditCardDetails.class),
#XmlElementRef(type=Wallet.class)
})
PaymentType paymentType;
The list of #XmlElementRefs can have any number of elements but all possibilities must be listed. CreditCardDetails and Wallet must be annotated with #XmlRootElement.
You can skip #XmlElementRefs annotation:
#XmlAnyElement(lax=true)
PaymentType paymentType;
but in that case make sure you have any required class in JAXB context, if you do not use registry annotate your class with PaymentType field with #XmlSeeAlso({CreditCardDetails.class, Wallet.class}).
I need to implement custom conversion for ID field in Company and Employee classes. I have already implemented custom converter extended from StrutsTypeConverter and it is successfully used to convert Company.ID field, but it does not work for Employee.ID.
Seems like the main problem is in conversion properties file. How should I specify converter class for employee ID field in conversion properties file?
MyAction-conversion.properties:
company.id = com.struts2.convertors.MyCustomConverter
company.??????.id = com.struts2.convertors.MyCustomConverter
MyAction:
public class MyAction extends ActionSupport {
private Company company;
public Company getCompany () {
return company;
}
public void setCompany (Company company) {
this.company= company;
}
#Override
public String execute() {
return SUCCESS;
}
}
Company:
public class Company {
private ID id;
private List<Employee> employees;
// getters and setters
}
Employee
public class Employee{
private ID id;
private String name;
// getters and setters
}
TypeConversion Annotation:
This annotation is used for class and application wide conversion rules.
The TypeConversion annotation can be applied at property and method level.
#TypeConversion(converter = “com.test.struts2.MyConverter”)
public void setAmount(String amount)
{
this.amount = amount;
}
This annotation specifies the location of one of my converters. literally, by using this annotation, I register my class com.test.struts2.MyConverter as a converter, and gets executed every time when setAmount(String amount) method is invoked.
Try the following by adding a converter for the ID type to the xwork-conversion.properties file
com.struts2.ID = com.struts2.convertors.MyCustomConverter