I am using Selma and I have the following class:
public class Customer
{
private int id;
private String email;
private String firstName;
private String lastName;
private Date registeredDate;
private List<Address> addresses;
}
I want to map it to:
public class Customer
{
private String id;
private String email;
private String firstName;
private String lastName;
private Date registeredDate;
private String company;
private Address address1;
private Address address2;
}
Is there any way to cast the (int) id to (String) id and to set the first address from the List to address1 and the second address to address2?
I was thinking of using an interceptor, but this way I will have to manually map the Address classes. Is there a way to use Selma to automatically map the address classes in the interceptor? For example:
public class CustomerCustomMapper
{
public void interceptMyCustomerToCustomer(com.mycode.domain.Customer source, Customer destination) {
if(source.getAddresses() != null && source.getAddresses().size() > 0)
{
com.mycode.domain.Address myAddress1 = source.getAddresses().get(0);
AddressMapper addressMapper = Selma.builder(AddressMapper.class).build();
Address address1 = addressMapper.mapAddress(myAddress1);
destination.setAddress1(address1);
// do the same for address2
}
}
EDIT
Regarding mapping the Address class I did it the way I showed above. I created an AddressMapper with the following code inside: Address toAddress(com.mycode.domain.Address address);
Then I created an addressMapper and used it to map the Address autimatically:
AddressMapper addressMapper = Selma.builder(AddressMapper.class).build();
As for the id, currently I have to create an interceptor for every class that I map (almost every class has an Id in it (SQL)), and manually set the id like so: destination.setId(Integer.toString(source.getId()));
It is quite frustrating actually, but sadly I can't find a better option.
for the list to Address the interceptor is the good answer.
For the int to String you can specify a custom mapper mapping from int to String (see http://www.selma-java.org/#custom-mapper).
But I would recommend using an abstract mapper instead of building a new mapper to map the Address. This way you'll be able to integrate your specific code inside the mapper and call the address mapper method directly (see http://www.selma-java.org/#abstract-mapper).
For the toString thing, you can also add a feature request to Github. I'll be glad to add this feature.
Related
I am connecting with many social networks for login in my application.
I have one DTO for each social network response.
public class GoogleUserInfo {
private String id;
private String firstName;
private String lastName;
private String email;
private AgeRange ageRange;
// more specific fields
}
public class FacebookUserInfo {
private String id;
private String firstName;
private String lastName;
private String email;
private String picture;
// more specific fields
}
public class AppleUserInfo {
private String id;
private String firstName;
private String lastName;
private String email;
private Boolean emailVerified;
// more specific fields
}
In each social network connector, I make similar steps to fetch the information, so I thought I could go with some DTO as follows:
public class SocialNetworkInfo {
protected String id;
protected String firstName;
protected String lastName;
protected String email;
}
Social networks DTOs could extend this to obtain the common fields. Then I could use this generic DTO to implement an abstract connector that deals with all the duplicate logic between connectors (make request, parse response, etc...):
abstract class AbstractConnector {
abstract SocialNetworkInfo fetchUserInfo(String networkId);
...
}
But I realized that above, in my service layer, I would need those specific fields to make some changes and operations.
SocialNetworkInfo networkUserInfo = facebookConnector.fetchUserInfo(facebookId);
facebookService.updatePicture(networkUserInfo.getPicture()); // can't access this specific field
What do you think that's the best way to go through this situation without casting and avoiding logic or DTO duplication?
Would love to hear your thoughts.
Thanks!
According to your situation, all social network models have the same nature, so it's ok if you move common attributes to shared class like CommonSocialInfo. Then I would recommend to provide interface for the connectors like:
interface SocialNetworkConnector<T extends SocialNetworkInfo> {
T fetchUserInfo(String userId);
}
Of course for common functionality(for connectors) is great idea to define common abstract class that implements interface above (implement Template pattern). I see that you are using FacebookService and related connector separately. I think that good idea to use composition in this case and make SocialNetworkService dependent on it connector. In short, FacebookService depends on FacebookConnecter and so on. Just a quick example:
public class FacebookService implements SocialNetworkService {
private final SocialNetworkConnector<FacebookSocialInfo> connector;
...
}
And if you need to implement multiple social service, you can use Factory pattern to produce required service, quick example:
interface SocialNetworkServiceFactory {
SocialNetworkService getFacebookService();
...
}
If you need more detailed help or you have troubles with understanding of the idea - feel free to ask!
If you don't want to use inheritance, I'd suggest to consider composition. The code can look as follows:
public class SocialNetworkInfo {
private String id;
private String firstName;
private String lastName;
private String email;
}
public class GoogleUserInfo {
private SocialNetworkInfo socialNetworkInfo;
private AgeRange ageRange;
// more specific fields
}
public class FacebookUserInfo {
private SocialNetworkInfo socialNetworkInfo;
private String picture;
// more specific fields
}
public class AppleUserInfo {
private SocialNetworkInfo socialNetworkInfo;
private Boolean emailVerified;
// more specific fields
}
I've got MultivaluedMap of custom object types which I am serializing using Gson. One of my requirement is to change the name of one of the object based on the length of the string to some other name.
I know that we can use annotations #SerializedName but it provides option for only one name alternative whereas I'm looking for two names for the same attribute and use it dynamically when serializing based on the string length.
How can I accomplish this?
Here's the outline of my custom object types:
Toplevel Class:
public class CompleteData{
private String country,
private String appId,
Private String userId,
private List<RecipientInfo> recipients;
private CustomDocument document;
<<setters//getters>>
public CompleteData(String country, String appId, String userId, List<RecipientInfo> recipients, CustomDocument document){
this.country=country..
..
..
}
CustomDocument Class:
public class CustomDocument{
String name;
String pageCount;
public CustomDocument(String name, int pageCount){
this.name = name;
this.pageCount = pageCount;
}
RecipientInfo Class:
public class RecipientInfo{
#serializedName("fullName")
String name;
String phoneNum;
public RecipientInfo(String name, String phoneNum){
this.name = name;
this.phoneNum = phoneNum;
}
}
Now I create List<CompleteData> completeData = new ArrayList<>();
Gather all the necessary information and add it to a MultivaluedMap as there are duplicate keys involved:
MultiValuedMap(<String, List<CompleteData>)
Now while using Gson to serialize this object, I want to change the "name" attribute in RecipientInfo class to be able to change dynamically based on the string length as fullname if the length is (>10 and <15) and fullNamewithSalu if the length is >20
Should I create a new class all together for this small change or is there a way I can serialize this object using Gson dynamically ?
Please help!
Thank you!
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 model like this:
public class Employee {
#JsonProperty("emplyee_id")
private Integer id;
#JsonProperty("emplyee_first_name")
private String firstName;
#JsonProperty("emplyee_last_name")
private String lastName;
#JsonProperty("emplyee_address")
private String address;
#JsonProperty("emplyee_age")
private Byte age;
#JsonProperty("emplyee_level")
private Byte level;
//getters and setters
}
now I need to create two JSONs using this (only) model.
the first one must like this for example:
{
"employee_id":101,
"employee_first_name":"Alex",
"employee_last_name":"Light",
"employee_age":null,
"employee_address":null
}
and the second one must like this for example:
{
"employee_id":101,
"employee_level":5
}
by the way, I already tested #JsonIgnore and #JsonInclude(JsonInclude.Include.NON_NULL).
the problem of the first one (as much as I know) is, those fields can't be included in other JSONs (for example if level get this annotation, it won't be included in the second JSON)
and the problem of the second one is, null values can't be included in JSON.
so can I keep null values and prevent some other property to be included in JSON without creating extra models? if the answer is yes, so how can I do it? if it's not I really appreciate if anyone gives me the best solution for this state.
thanks very much.
it could be useful for you using #JsonView annotation
public class Views {
public static class Public {
}
public static class Base {
}
}
public class Employee {
#JsonProperty("emplyee_id")
#JsonView({View.Public.class,View.Base.class})
private Integer id;
#JsonProperty("emplyee_first_name")
#JsonView(View.Public.class)
private String firstName;
#JsonProperty("emplyee_last_name")
#JsonView(View.Public.class)
private String lastName;
#JsonProperty("emplyee_address")
private String address;
#JsonProperty("emplyee_age")
private Byte age;
#JsonProperty("emplyee_level")
#JsonView(View.Base.class)
private Byte level;
//getters and setters
}
in your json response add #JsonView(Public/Base.class) it will return based on jsonview annotations
//requestmapping
#JsonView(View.Public.class)
public ResponseEntity<Employee> getEmployeeWithPublicView(){
//do something
}
response:
{
"employee_id":101,
"employee_first_name":"Alex",
"employee_last_name":"Light",
"employee_age":null,
"employee_address":null
}
for the second one
//requestmapping
#JsonView(View.Base.class)
public ResponseEntity<Employee> getEmployeeWithBaseView(){
//do something
}
response
{
"employee_id":101,
"employee_level":5
}
I have a class named Customer which stores the following objects:
private String CustomerFirstName
private String CustomerLastName
private String CustomerID
private String CustomerEmail
now in order to pass data to jasper report, I decided to create an array list which contains these objects, so :
import java.util.ArrayList;
import java.util.Collection;
/* This is CustomerDataSource.java file */
public class CustomerDataSource {
public static Collection<Customer> loadCustomers() throws Exception {
Collection<Customer> customers = new ArrayList<Customer>();
Customer customer = new customer (
/* I need help getting the objects CustomerFirstName / CustomerLastName and etc */
);
customer.addBilling(new Billing ( /* Adding billing info */ ));
customer.getBilling(new Billing ( /* I need to get the object's values*/));
customer.balOwing();
customers.add (customer);
return customers;
}
}
can someone please explain how to add the objects in Customer.java to the array list? (and in general since I need to add objects from different files as well. Thank you
So as I see your problem in your comment, you want to create a constructor.
In your Costumer class
public Costumer(String firstName, String lastName, String ID, String email) {
this.CostumerFirstName = firstName;
this.CostumerLastName = lastName;
this.CostumerID = ID;
this.CostumerEmail = email;
}
So then you can create a new costumer like that:
Customer customer = new Customer ("SampleFirstName","SampleLastName","0000","address#web.com");
You could even add the costumer automatically to the ArrayList by adding it in the constructor.
From your comment, I am guessing you would like to use a constructor?
You will have to add a constructor on your Customer.java.
public Customer(String firstName, String lastName, String id, String email){
this.CustomerFirstName = firstName;
this.CustomerLastName = lastName;
this.CustomerID = id;
this.CustomerEmail = email;
}
You might want to make getter/setter methods for access to above variables.
ArrayList<E>.get(i) performs virtually the exact same function as [] in static arrays. The only difference between the two is that ArrayList<E>.get(i) is simply adapted into the object context. In other words, you can dereference it.
First, you'll need to change the privacy of Customer's fields to public to give the ArrayList<Customers> object access to it.
Then you'll be able to retrieve your class' fields with simply:
customers.get(index).FirstName //or whatever other field