package net.techreadiness.service.object.mapping; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.inject.Inject; import ma.glasnost.orika.MapperFacade; import ma.glasnost.orika.MapperFactory; import ma.glasnost.orika.impl.DefaultMapperFactory; import net.techreadiness.persistence.BaseEntity; import net.techreadiness.persistence.ServiceObjectMapped; import net.techreadiness.persistence.dao.GenericDAO; import net.techreadiness.persistence.domain.ContactDO; import net.techreadiness.persistence.domain.DeviceDO; import net.techreadiness.persistence.domain.FileDO; import net.techreadiness.persistence.domain.OrgDO; import net.techreadiness.persistence.domain.ScopeDO; import net.techreadiness.persistence.domain.UserDO; import net.techreadiness.persistence.domain.UserOrgDO; import net.techreadiness.persistence.domain.UserRoleDO; import net.techreadiness.service.object.BaseObject; import net.techreadiness.service.object.Contact; import net.techreadiness.service.object.Device; import net.techreadiness.service.object.File; import net.techreadiness.service.object.Org; import net.techreadiness.service.object.Scope; import net.techreadiness.service.object.User; import net.techreadiness.service.object.UserOrg; import net.techreadiness.service.object.UserRole; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @Service public class MappingServiceImpl implements MappingService { @Inject GenericDAO genericDao; private MapperFactory factory = null; public MappingServiceImpl() { buildFactory(); } private MapperFactory getFactory() { if (factory == null) { buildFactory(); } return factory; } /** * By using the ClassMapBuilder.byDefault(), we are relying on the automatic mapping of identically named fields (much as * you would get with BeanUtils.copyProperties()), as well as any nested classes. The service objects have core fields * that are the same as the DO object they represent as a base. * * We then customize the class map to work with extended fields that don't fit the simple model. Because of this, mapper * classes are not needed for all of our objects. Some are fulfilled by the base mapping provided by orika. Orika handles * any two classes thrown at it, mapping what it can. */ private void buildFactory() { // Use for troubleshooting. This will make Orika write the generated mapping // file out to the filesystem. // System.setProperty(OrikaSystemProperties.WRITE_SOURCE_FILES,"true"); // System.setProperty(OrikaSystemProperties.WRITE_CLASS_FILES,"true"); factory = new DefaultMapperFactory.Builder().build(); factory.classMap(ContactDO.class, Contact.class).byDefault().customize(new ContactDOandContactMapper()).register(); factory.classMap(OrgDO.class, Org.class).byDefault().customize(new OrgDOandOrgMapper()).register(); factory.classMap(ScopeDO.class, Scope.class).byDefault().customize(new ScopeDOandScopeMapper()).register(); factory.classMap(UserDO.class, User.class).byDefault().customize(new UserDOandUserMapper()).register(); factory.classMap(DeviceDO.class, Device.class).byDefault().customize(new DeviceDOandDeviceMapper()).register(); factory.classMap(FileDO.class, File.class).byDefault().customize(new FileDOandFileMapper()).register(); factory.classMap(UserRoleDO.class, UserRole.class).byDefault().customize(new UserRoleDOtoUserRoleMapper()) .register(); factory.classMap(UserOrgDO.class, UserOrg.class).byDefault().customize(new UserOrgDOToUserOrgMapper()).register(); } @Override public <T extends BaseEntity> T map(BaseObject<T> object) { if (object == null) { return null; } return getFactory().getMapperFacade().map(object, object.getBaseEntityType()); } @Override public <T extends BaseEntity, U extends BaseObject<T>> U map(T entity, Class<U> serviceObjectType) { if (entity == null) { return null; } U map = getFactory().getMapperFacade().map(entity, serviceObjectType); return map; } @Override public <T extends BaseEntity, U extends BaseObject<T>> U map(T entity) { if (entity == null) { return null; } U u = (U) getFactory().getMapperFacade().map(entity, getServiceObjectClass(entity)); return u; } @Override public <T extends BaseEntity> List<T> mapToDOList(Iterable<BaseObject<T>> list) { if (list == null) { return null; } Iterator<BaseObject<T>> it = list.iterator(); BaseObject<T> o = null; if (it.hasNext()) { o = it.next(); } if (o != null) { List<T> t = getFactory().getMapperFacade().mapAsList(list, o.getBaseEntityType()); return t; } return null; } @Override public <T extends BaseEntity, U extends BaseObject<T>> List<U> mapFromDOList(Iterable<T> domainObjects) { if (domainObjects == null) { return null; } else if (Iterables.isEmpty(domainObjects)) { return Collections.emptyList(); } BaseEntity entity = Iterables.getFirst(domainObjects, null); return (List<U>) getFactory().getMapperFacade().mapAsList(domainObjects, getServiceObjectClass(entity)); } @Override public <T extends BaseEntity, U extends BaseObject<T>> List<Map<String, String>> mapFromDOListToMap( Iterable<T> domainObjects) { List<U> l = mapFromDOList(domainObjects); List<Map<String, String>> list = Lists.newArrayList(); if (l != null) { for (U u : l) { list.add(u.getAsMap()); } } return list; } private static Class<?> getServiceObjectClass(Object o) { if (o instanceof ServiceObjectMapped) { return ((ServiceObjectMapped) o).getServiceObjectType(); } throw new IllegalArgumentException("Trying to map a class not implementing ServiceObjectMapped."); } @Override public <T extends BaseEntity> String toStringRepresentation(BaseObject<T> object) { Long id = object.getId(); if (id == null) { return "NEW"; } return id.toString(); } @Override @Transactional(readOnly = true) public <T extends BaseEntity, U extends BaseObject<T>> U fromStringRepresentation(Class<U> serviceObjectType, String representation) { Class<T> domainObjectClass; try { domainObjectClass = serviceObjectType.newInstance().getBaseEntityType(); } catch (Exception e) { throw new RuntimeException(e); } T domainObject; if ("NEW".equals(representation)) { try { domainObject = domainObjectClass.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } else { domainObject = genericDao.find(domainObjectClass, Long.valueOf(representation)); } return map(domainObject, serviceObjectType); } @Override public MapperFacade getMapper() { return getFactory().getMapperFacade(); } }