io.mosip.pms.common.util.MapperUtils Maven / Gradle / Ivy
package io.mosip.pms.common.util;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import org.springframework.stereotype.Component;
import io.mosip.kernel.core.dataaccess.exception.DataAccessLayerException;
import io.mosip.kernel.core.util.EmptyCheckUtils;
import io.mosip.pms.common.dto.SearchAuthPolicy;
import io.mosip.pms.common.entity.AuthPolicy;
import io.mosip.pms.common.entity.BaseEntity;
/**
* MapperUtils class provides methods to map or copy values from source object
* to destination object.
*
* @author Bal Vikash Sharma
* @author Urvil Joshi
* @since 1.0.0
* @see MapperUtils
*
*/
@Component
@SuppressWarnings("unchecked")
public class MapperUtils {
/*
* @Autowired private ObjectMapper mapper;
*/
private MapperUtils() {
super();
}
private static final String UTC_DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
private static final String SOURCE_NULL_MESSAGE = "source should not be null";
private static final String DESTINATION_NULL_MESSAGE = "destination should not be null";
/**
* This flag is used to restrict copy null values.
*/
private static Boolean mapNullValues = Boolean.TRUE;
/**
* Parse a date string of pattern UTC_DATETIME_PATTERN into
* {@link LocalDateTime}
*
* @param dateTime of type {@link String} of pattern UTC_DATETIME_PATTERN
* @return a {@link LocalDateTime} of given pattern
*/
public static LocalDateTime parseToLocalDateTime(String dateTime) {
return LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern(UTC_DATETIME_PATTERN));
}
/*
* #############Public method used for mapping################################
*/
/**
* This method map the values from source
to
* destination
if name and type of the fields inside the given
* parameters are same.If any of the parameters are null
this
* method return null
.This method internally check whether the
* source or destinationClass is DTO or an Entity type and map accordingly. If
* any {@link Collection} type or Entity type field is their then only matched
* name fields value will be set but not the embedded IDs and super class
* values.
*
* @param is a type parameter
* @param is a type parameter
* @param source which value is going to be mapped
* @param destination where values is going to be mapped
* @param mapNullValues by default marked as true so, it will map null values
* but if marked as false then null values will be ignored
* @return the destination
object
* @throws NullPointerException if either source
or
* destination
is null
*/
public static D map(final S source, D destination, Boolean mapNullValues) {
MapperUtils.mapNullValues = mapNullValues;
return map(source, destination);
}
/**
* This method map the values from source
to
* destination
if name and type of the fields inside the given
* parameters are same.If any of the parameters are null
this
* method return null
.This method internally check whether the
* source or destinationClass is DTO or an Entity type and map accordingly. If
* any {@link Collection} type or Entity type field is their then only matched
* name fields value will be set but not the embedded IDs and super class
* values.
*
* @param is a type parameter
* @param is a type parameter
* @param source which value is going to be mapped
* @param destination where values is going to be mapped
* @return the destination
object
* @throws NullPointerException if either source
or
* destination
is null
*/
public static D map(final S source, D destination) {
Objects.requireNonNull(source, SOURCE_NULL_MESSAGE);
Objects.requireNonNull(destination, DESTINATION_NULL_MESSAGE);
try {
mapValues(source, destination);
} catch (IllegalAccessException | InstantiationException e) {
throw new DataAccessLayerException("KER-MSD-991", "Exception in mapping vlaues from source : "
+ source.getClass().getName() + " to destination : " + destination.getClass().getName(), e);
}
return destination;
}
/**
* This method takes source
and destinationClass
, take
* all values from source and create an object of destinationClass
* and map all the values from source to destination if field name and type is
* same.This method internally check whether the source or destinationClass is
* DTO or an Entity type and map accordingly.If any {@link Collection} type or
* Entity type field is their then only matched name fields value will be set
* but not the embedded IDs and super class values.
*
* @param is a type parameter
* @param is a type parameter
* @param source which value is going to be mapped
* @param destinationClass where values is going to be mapped
* @return the object of destinationClass
* @throws DataAccessLayerException if exception occur during creating of
* destinationClass
object
* @throws NullPointerException if either source
or
* destinationClass
is null
*/
public static D map(final S source, Class destinationClass) {
Objects.requireNonNull(source, SOURCE_NULL_MESSAGE);
Objects.requireNonNull(destinationClass, "destination class should not be null");
Object destination = null;
try {
destination = destinationClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new DataAccessLayerException("KER-MSD-991", "Exception in mapping vlaues from source : "
+ source.getClass().getName() + " to destination : " + destinationClass.getClass().getName(), e);
}
return (D) map(source, destination);
}
/**
* This method takes sourceList
and destinationClass
,
* take all values from source and create an object of
* destinationClass
and map all the values from source to
* destination if field name and type is same.
*
* @param is a type parameter
*
* @param is a type parameter
* @param sourceList which value is going to be mapped
* @param destinationClass where values is going to be mapped
* @return list of destinationClass objects
* @throws DataAccessLayerException if exception occur during creating of
* destinationClass
object
* @throws NullPointerException if either sourceList
or
* destinationClass
is null
*/
public static List mapAll(final Collection sourceList, Class destinationClass) {
Objects.requireNonNull(sourceList, "sourceList should not be null");
Objects.requireNonNull(destinationClass, "destinationClass should not be null");
return sourceList.stream().map(entity -> map(entity, destinationClass)).collect(Collectors.toList());
}
/**
* This method map values of source
object to
* destination
object. It will map field values having same name
* and same type for the fields. It will not map any field which is static or
* final.It will simply ignore those values.
*
* @param is a type parameter
*
* @param is a type parameter
* @param source is any object which should not be null and have data which
* is going to be copied
* @param destination is an object in which source field values is going to be
* matched
*
* @throws DataAccessLayerException if error raised during mapping values
* @throws NullPointerException if either source
or
* destination
is null
*/
public static void mapFieldValues(S source, D destination) {
Objects.requireNonNull(source, SOURCE_NULL_MESSAGE);
Objects.requireNonNull(destination, DESTINATION_NULL_MESSAGE);
Field[] sourceFields = source.getClass().getDeclaredFields();
Field[] destinationFields = destination.getClass().getDeclaredFields();
mapFieldValues(source, destination, sourceFields, destinationFields);
}
/**
* Map values from {@link BaseEntity} class source object to destination or vice
* versa and this method will be used to map {@link BaseEntity} values from
* entity to entity. Like when both source
and
* destination
are object which extends {@link BaseEntity}.
*
* @param is a type parameter
* @param is a type parameter
* @param source which value is going to be mapped
* @param destination where values is going to be mapped
*/
public static void setBaseFieldValue(S source, D destination) {
Objects.requireNonNull(source, SOURCE_NULL_MESSAGE);
Objects.requireNonNull(destination, DESTINATION_NULL_MESSAGE);
String sourceSupername = source.getClass().getSuperclass().getName();// super class of source object
String destinationSupername = destination.getClass().getSuperclass().getName();// super class of destination
// object
String baseEntityClassName = source.getClass().getName();// base entity fully qualified name
String objectClassName = Object.class.getName();// object class fully qualified name
String baseDtoClassName = source.getClass().getName();// base entity fully qualified name
if (sourceSupername.equals(baseEntityClassName) && destinationSupername.equals(baseDtoClassName)) {
Field[] sourceFields = source.getClass().getSuperclass().getDeclaredFields();
Field[] destinationFields = destination.getClass().getSuperclass().getDeclaredFields();
mapFieldValues(source, destination, sourceFields, destinationFields);
sourceFields = source.getClass().getDeclaredFields();
mapFieldValues(source, destination, sourceFields, destinationFields);
return;
}
if (sourceSupername.equals(baseDtoClassName) && destinationSupername.equals(baseEntityClassName)) {
Field[] sourceFields = source.getClass().getSuperclass().getDeclaredFields();
Field[] destinationFields = destination.getClass().getSuperclass().getDeclaredFields();
mapFieldValues(source, destination, sourceFields, destinationFields);
destinationFields = destination.getClass().getDeclaredFields();
mapFieldValues(source, destination, sourceFields, destinationFields);
return;
}
// if source is an entity
if (sourceSupername.equals(baseEntityClassName) && !destinationSupername.equals(baseEntityClassName)) {
Field[] sourceFields = source.getClass().getSuperclass().getDeclaredFields();
Field[] destinationFields = destination.getClass().getDeclaredFields();
mapFieldValues(source, destination, sourceFields, destinationFields);
} else if (destinationSupername.equals(baseEntityClassName) && !sourceSupername.equals(baseEntityClassName)) {
// if destination is an entity
Field[] sourceFields = source.getClass().getDeclaredFields();
Field[] destinationFields = destination.getClass().getSuperclass().getDeclaredFields();
mapFieldValues(source, destination, sourceFields, destinationFields);
} else {
if (!sourceSupername.equals(objectClassName) && !destinationSupername.equals(objectClassName)) {
Field[] sourceFields = source.getClass().getSuperclass().getDeclaredFields();
Field[] destinationFields = destination.getClass().getSuperclass().getDeclaredFields();
mapFieldValues(source, destination, sourceFields, destinationFields);
}
}
}
/*
* #############Private method used for mapping################################
*/
/**
* Map values from source object to destination object.
*
* @param is a type parameter
* @param is a type parameter
* @param source which value is going to be mapped
* @param destination where values is going to be mapped
* @throws InstantiationException if not able to create instance of field having
* annotation {@link EmbeddedId}
* @throws IllegalAccessException if provided fields are not accessible
*/
private static void mapValues(S source, D destination)
throws IllegalAccessException, InstantiationException {
mapFieldValues(source, destination);// this method simply map values if field name and type are same
if (source.getClass().isAnnotationPresent(Entity.class)) {
mapEntityToDto(source, destination);
} else {
mapDtoToEntity(source, destination);
}
}
/**
* This method map source DTO to a class object which extends {@link BaseEntity}
*
* @param is a type parameter
* @param is a type parameter
* @param source which value is going to be mapped
* @param destination where values is going to be mapped
* @throws InstantiationException if not able to create instance of field having
* annotation {@link EmbeddedId}
* @throws IllegalAccessException if provided fields are not accessible
*/
private static void mapDtoToEntity(S source, D destination)
throws InstantiationException, IllegalAccessException {
Field[] fields = destination.getClass().getDeclaredFields();
setBaseFieldValue(source, destination);// map super class values
for (Field field : fields) {
/**
* Map DTO matching field values to super class field values
*/
if (field.isAnnotationPresent(EmbeddedId.class)) {
Object id = field.getType().newInstance();
mapFieldValues(source, id);
field.setAccessible(true);
field.set(destination, id);
field.setAccessible(false);
break;
}
}
}
/**
* Map source which extends {@link BaseEntity} to a DTO object.
*
* @param is a type parameter
* @param is a type parameter
* @param source which value is going to be mapped
* @param destination where values is going to be mapped
* @throws IllegalAccessException if provided fields are not accessible
*/
private static void mapEntityToDto(S source, D destination) throws IllegalAccessException {
Field[] sourceFields = source.getClass().getDeclaredFields();
/*
* Here source is a Entity so we need to take values from Entity object and set
* the matching fields in the destination object mostly an DTO.
*/
boolean isIdMapped = false;// a flag to check if there any composite key is present and is mapped
boolean isSuperMapped = false;// a flag to check is class extends the BaseEntity and is mapped
for (Field sfield : sourceFields) {
sfield.setAccessible(true);// mark accessible true because fields my be private, for safety
if (!isIdMapped && sfield.isAnnotationPresent(EmbeddedId.class)) {
/**
* Map the composite key values from source to destination if field name is same
*/
/**
* Take the field and get the composite key object and map all values to
* destination object
*/
mapFieldValues(sfield.get(source), destination);
sfield.setAccessible(false);
isIdMapped = true;// set flag so no need to check and map again
} else if (!isSuperMapped) {
setBaseFieldValue(source, destination);// this method check whether source is entity or destination
// and maps values accordingly
isSuperMapped = true;
}
}
}
/**
* Map values from source field to destination.
*
* @param is a type parameter
* @param is a type parameter
* @param source which value is going to be mapped
* @param destination where values is going to be mapped
* @param sf source fields
* @param dtf destination fields
*/
private static void mapFieldValues(S source, D destination, Field[] sourceFields,
Field[] destinationFields) {
try {
for (Field sfield : sourceFields) {
// Do not set values either static or final
if (Modifier.isStatic(sfield.getModifiers()) || Modifier.isFinal(sfield.getModifiers())) {
continue;
}
// make field accessible possibly private
sfield.setAccessible(true);
for (Field dfield : destinationFields) {
Class> sourceType = sfield.getType();
Class> destinationType = dfield.getType();
// map only those field whose name and type is same
if (sfield.getName().equals(dfield.getName()) && sourceType.equals(destinationType)) {
// for normal field values
dfield.setAccessible(true);
setFieldValue(source, destination, sfield, dfield);
break;
}
}
}
} catch (IllegalAccessException e) {
throw new DataAccessLayerException("KER-MSD-993", "Exception raised while mapping values form "
+ source.getClass().getName() + " to " + destination.getClass().getName(), e);
}
}
/**
* Take value from source field and insert value into destination field.
*
* @param is a type parameter
* @param is a type parameter
* @param source which value is going to be mapped
* @param destination where values is going to be mapped
* @param sf source fields
* @param dtf destination fields
* @throws IllegalAccessException if provided fields are not accessible
*/
private static void setFieldValue(S source, D destination, Field sf, Field dtf)
throws IllegalAccessException {
// check whether user wants to map null values into destination object or not
if (!mapNullValues && EmptyCheckUtils.isNullEmpty(sf.get(source))) {
return;
}
dtf.set(destination, sf.get(source));
dtf.setAccessible(false);
sf.setAccessible(false);
}
public static List mapAuthPolicySearch(List authPolicies){
Objects.requireNonNull(authPolicies);
List authPoliciesList=new ArrayList<>();
authPolicies.forEach(authPolicy -> {
SearchAuthPolicy searchAuthPolicy=new SearchAuthPolicy();
searchAuthPolicy.setCrBy(authPolicy.getCrBy());
searchAuthPolicy.setCrDtimes(authPolicy.getCrDtimes());
searchAuthPolicy.setDelDtimes(authPolicy.getDelDtimes());
searchAuthPolicy.setDesc(authPolicy.getDescr());
searchAuthPolicy.setId(authPolicy.getId());
searchAuthPolicy.setIsActive(authPolicy.getIsActive());
searchAuthPolicy.setIsDeleted(authPolicy.getIsDeleted());
searchAuthPolicy.setName(authPolicy.getName());
searchAuthPolicy.setPolicies(authPolicy.getPolicyFileId());
searchAuthPolicy.setPolicyGroupId(authPolicy.getPolicyGroup().getId());
searchAuthPolicy.setPolicyGroupName(authPolicy.getPolicyGroup().getName());
searchAuthPolicy.setPolicyType(authPolicy.getPolicy_type());
searchAuthPolicy.setSchema(authPolicy.getPolicySchema());
searchAuthPolicy.setUpdBy(authPolicy.getUpdBy());
searchAuthPolicy.setUpdDtimes(authPolicy.getUpdDtimes());
searchAuthPolicy.setValidFromDate(authPolicy.getValidFromDate());
searchAuthPolicy.setValidToDate(authPolicy.getValidToDate());
searchAuthPolicy.setVersion(authPolicy.getVersion());
authPoliciesList.add(searchAuthPolicy);
});
return authPoliciesList;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy