已应用于实际项目:1.thrift对象与dto之间的互转
2.pojo与dto之间的互转
3.pojo与vo之间的互转
1.核心转换工具类,对特别复杂类型不做处理,因为业务场景还未覆盖
package littlehow.convert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* PojoConvertUtil
*
* @author littlehow
* @time 2017-05-03 16:54
*/
public class PojoConvertUtil {
private static Logger logger = LoggerFactory.getLogger(PojoConvertUtil.class);
/**
* 变量缓存
*/
private static final Map> cacheFields = new ConcurrentHashMap<>();
private static final Set basicClass = new HashSet<>();
static {
basicClass.add(Integer.class);
basicClass.add(Character.class);
basicClass.add(Byte.class);
basicClass.add(Float.class);
basicClass.add(Double.class);
basicClass.add(Boolean.class);
basicClass.add(Long.class);
basicClass.add(Short.class);
basicClass.add(String.class);
basicClass.add(BigDecimal.class);
}
/**
* 将具有相同属性的类型进行转换
* @param orig
* @param
* @return
*/
public static T convertPojo(Object orig, Class targetClass) {
try {
T target = targetClass.newInstance();
/** 获取源对象的所有变量 */
Field[] fields = orig.getClass().getDeclaredFields();
for (Field field : fields) {
if (isStatic(field)) continue;
/** 获取目标方法 */
Field targetField = getTargetField(targetClass, field.getName());
if (targetField == null) continue;
Object value = getFiledValue(field, orig);
if (value == null) continue;
Class type1 = field.getType();
Class type2 = targetField.getType();
//两个类型是否相同
boolean sameType = type1.equals(type2);
if (isBasicType(type1)) {
if (sameType) setFieldValue(targetField, target, value);
} else if (value instanceof Map && Map.class.isAssignableFrom(type2)){//对map
setMap((Map)value, field, targetField, target);
} else if (value instanceof Set && Set.class.isAssignableFrom(type2)) {//对set
setCollection((Collection)value, field, targetField, target);
} else if (value instanceof List && List.class.isAssignableFrom(type2)) {//对list
setCollection((Collection)value, field, targetField, target);
} else if (value instanceof Enum && Enum.class.isAssignableFrom(type2)) {//对enum
setEnum((Enum)value, field, targetField, target);
} else if (value instanceof java.util.Date &&
java.util.Date.class.isAssignableFrom(type2)) {//对日期类型,不处理如joda包之类的扩展时间,不处理calendar
setDate((Date)value, targetField, type2, target, sameType);
}
}
return target;
} catch (Throwable t) {
logger.error("转换失败:" + t.getMessage());
throw new RuntimeException(t.getMessage());
}
}
/**
* 获取字段值
* @param field
* @param obj
* @return
*/
private static Object getFiledValue(Field field, Object obj) throws IllegalAccessException {
//获取原有的访问权限
boolean access = field.isAccessible();
try {
//设置可访问的权限
field.setAccessible(true);
return field.get(obj);
} finally {
//恢复访问权限
field.setAccessible(access);
}
}
/**
* 设置方法值
* @param field
* @param obj
* @param value
* @throws IllegalAccessException
*/
private static void setFieldValue(Field field, Object obj, Object value) throws IllegalAccessException {
//获取原有的访问权限
boolean access = field.isAccessible();
try {
//设置可访问的权限
field.setAccessible(true);
field.set(obj, value);
} finally {
//恢复访问权限
field.setAccessible(access);
}
}
/**
* 转换list
* @param orig
* @param targetClass
* @param
* @return
*/
public static List convertPojos(List orig, Class targetClass) {
List list = new ArrayList<>(orig.size());
for (Object object : orig) {
list.add(convertPojo(object, targetClass));
}
return list;
}
/**
* 设置Map
* @param value
* @param origField
* @param targetField
* @param targetObject
* @param
*/
private static void setMap(Map value, Field origField, Field targetField, T targetObject) throws IllegalAccessException, InstantiationException{
Type origType = origField.getGenericType();
Type targetType = targetField.getGenericType();
if (origType instanceof ParameterizedType && targetType instanceof ParameterizedType) {//泛型类型
ParameterizedType origParameterizedType = (ParameterizedType)origType;
Type[] origTypes = origParameterizedType.getActualTypeArguments();
ParameterizedType targetParameterizedType = (ParameterizedType)targetType;
Type[] targetTypes = targetParameterizedType.getActualTypeArguments();
if (origTypes != null && origTypes.length == 2 && targetTypes != null && targetTypes.length == 2) {//正常泛型,查看第二个泛型是否不为基本类型
Class clazz = (Class)origTypes[1];
if (!isBasicType(clazz) && !clazz.equals(targetTypes[1])) {//如果不是基本类型并且泛型不一致,则需要继续转换
Set entries = value.entrySet();
Map targetMap = value.getClass().newInstance();
for (Map.Entry entry : entries) {
targetMap.put(entry.getKey(), convertPojo(entry.getValue(), (Class) targetTypes[1]));
}
setFieldValue(targetField, targetObject, targetMap);
return;
}
}
}
setFieldValue(targetField, targetObject, value);
}
/**
* 设置集合
* @param value
* @param origField
* @param targetField
* @param targetObject
* @param
* @throws IllegalAccessException
* @throws InstantiationException
*/
private static void setCollection(Collection value, Field origField, Field targetField, T targetObject) throws IllegalAccessException, InstantiationException{
Type origType = origField.getGenericType();
Type targetType = targetField.getGenericType();
if (origType instanceof ParameterizedType && targetType instanceof ParameterizedType) {//泛型类型
ParameterizedType origParameterizedType = (ParameterizedType)origType;
Type[] origTypes = origParameterizedType.getActualTypeArguments();
ParameterizedType targetParameterizedType = (ParameterizedType)targetType;
Type[] targetTypes = targetParameterizedType.getActualTypeArguments();
if (origTypes != null && origTypes.length == 1 && targetTypes != null && targetTypes.length == 1) {//正常泛型,查看第二个泛型是否不为基本类型
Class clazz = (Class)origTypes[0];
if (!isBasicType(clazz) && !clazz.equals(targetTypes[0])) {//如果不是基本类型并且泛型不一致,则需要继续转换
Collection collection = value.getClass().newInstance();
for (Object obj : value) {
collection.add(convertPojo(obj, (Class) targetTypes[0]));
}
setFieldValue(targetField, targetObject, collection);
return;
}
}
}
setFieldValue(targetField, targetObject, value);
}
/**
* 设置枚举类型
* @param value
* @param origField
* @param targetField
* @param targetObject
* @param
*/
private static void setEnum(Enum value, Field origField, Field targetField, T targetObject) throws Exception{
if (origField.equals(targetField)) {
setFieldValue(targetField, targetObject, value);
} else {
//枚举类型都具有一个static修饰的valueOf方法
Method method = targetField.getType().getMethod("valueOf", String.class);
setFieldValue(targetField, targetObject, method.invoke(null, value.toString()));
}
}
/**
* 设置日期类型
* @param value
* @param targetField
* @param targetFieldType
* @param targetObject
* @param
*/
private static void setDate(Date value, Field targetField, Class targetFieldType, T targetObject, boolean sameType) throws IllegalAccessException {
Date date = null;
if (sameType) {
date = value;
} else if (targetFieldType.equals(java.sql.Date.class)) {
date = new java.sql.Date(value.getTime());
} else if (targetFieldType.equals(java.util.Date.class)) {
date = new Date(value.getTime());
} else if (targetFieldType.equals(java.sql.Timestamp.class)) {
date = new java.sql.Timestamp(value.getTime());
}
setFieldValue(targetField, targetObject, date);
}
/**
* 获取适配方法
* @param clazz
* @param fieldName
* @return
*/
public static Field getTargetField(Class clazz, String fieldName) {
String classKey = clazz.getName();
Map fieldMap = cacheFields.get(classKey);
if (fieldMap == null) {
fieldMap = new HashMap<>();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (isStatic(field)) continue;
fieldMap.put(field.getName(), field);
}
cacheFields.put(classKey, fieldMap);
}
return fieldMap.get(fieldName);
}
/**
* 确实是否为基础类型
* @param clazz
* @return
*/
public static boolean isBasicType(Class clazz) {
return clazz.isPrimitive() || basicClass.contains(clazz);
}
/**
* 判断变量是否有静态修饰符static
* @param field
* @return
*/
public static boolean isStatic(Field field) {
return (8 & field.getModifiers()) == 8;
}
}
下面这个类是便于输出展示的,因为只是用于打印,所以不做效率考虑
package littlehow.convert;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* SimpleToStringParent
*
* @author littlehow
* @time 2017-05-04 10:40
*/
public class SimpleToStringParent {
@Override
public String toString() {
try {
StringBuilder stringBuilder = new StringBuilder("{");
Field[] fields = this.getClass().getDeclaredFields();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (Field field : fields) {
Object value = getFiledValue(field, this);
if (value == null) continue;
if (value instanceof Date) {
//这里也可以直接转为时间戳
value = dateFormat.format((Date)value);
}
stringBuilder.append(field.getName()).append("=").append(value).append(",");
}
String returnValue = stringBuilder.toString();
if (returnValue.length() > 1) {
returnValue = returnValue.substring(0, returnValue.length() - 1);
}
return this.getClass().getSimpleName() + returnValue + "}";
} catch (Exception e) {
// skip
}
return this.getClass().getSimpleName() + "{}";
}
/**
* 获取属性值
* @param field
* @param obj
* @return
* @throws IllegalAccessException
*/
private Object getFiledValue(Field field, Object obj) throws IllegalAccessException {
//获取原有的访问权限
boolean access = field.isAccessible();
try {
//设置可访问的权限
field.setAccessible(true);
return field.get(obj);
} finally {
//恢复访问权限
field.setAccessible(access);
}
}
}
测试用的4个pojo
1.产品类
package littlehow.convert.pojo;
import littlehow.convert.SimpleToStringParent;
import java.util.List;
/**
* Product
*
* @author littlehow
* @time 2017-05-04 09:15
*/
public class Product extends SimpleToStringParent {
private Integer productId;
private String generalName;
private String factoryName;
private String unit;
private String specification;
private Integer category;
private List- items;
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public String getGeneralName() {
return generalName;
}
public void setGeneralName(String generalName) {
this.generalName = generalName;
}
public String getFactoryName() {
return factoryName;
}
public void setFactoryName(String factoryName) {
this.factoryName = factoryName;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
public String getSpecification() {
return specification;
}
public void setSpecification(String specification) {
this.specification = specification;
}
public List
- getItems() {
return items;
}
public void setItems(List
- items) {
this.items = items;
}
public Integer getCategory() {
return category;
}
public void setCategory(Integer category) {
this.category = category;
}
}
2.商品类
package littlehow.convert.pojo;
import littlehow.convert.SimpleToStringParent;
import java.util.Date;
import java.util.List;
/**
* Item
*
* @author littlehow
* @time 2017-05-04 09:15
*/
public class Item extends SimpleToStringParent {
private Long itemId;
private String itemName;
private Byte status;
private Boolean deleted;
private Date createTime;
private List skus;
public Long getItemId() {
return itemId;
}
public void setItemId(Long itemId) {
this.itemId = itemId;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public Byte getStatus() {
return status;
}
public void setStatus(Byte status) {
this.status = status;
}
public Boolean getDeleted() {
return deleted;
}
public void setDeleted(Boolean deleted) {
this.deleted = deleted;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public List getSkus() {
return skus;
}
public void setSkus(List skus) {
this.skus = skus;
}
}
3.最小库存单位sku
package littlehow.convert.pojo;
import littlehow.convert.SimpleToStringParent;
import java.lang.reflect.Field;
/**
* Sku
*
* @author littlehow
* @time 2017-05-04 09:15
*/
public class Sku extends SimpleToStringParent {
private Long skuId;
private Byte status;
private Boolean deleted;
private Double price;
private Double promoPrice;
private Integer inventory;
private Integer minBuy;
private Integer blockInventory;
private Color skuColor;
public Long getSkuId() {
return skuId;
}
public void setSkuId(Long skuId) {
this.skuId = skuId;
}
public Byte getStatus() {
return status;
}
public void setStatus(Byte status) {
this.status = status;
}
public Boolean getDeleted() {
return deleted;
}
public void setDeleted(Boolean deleted) {
this.deleted = deleted;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Double getPromoPrice() {
return promoPrice;
}
public void setPromoPrice(Double promoPrice) {
this.promoPrice = promoPrice;
}
public Integer getInventory() {
return inventory;
}
public void setInventory(Integer inventory) {
this.inventory = inventory;
}
public Integer getMinBuy() {
return minBuy;
}
public void setMinBuy(Integer minBuy) {
this.minBuy = minBuy;
}
public Integer getBlockInventory() {
return blockInventory;
}
public void setBlockInventory(Integer blockInventory) {
this.blockInventory = blockInventory;
}
public Color getSkuColor() {
return skuColor;
}
public void setSkuColor(Color skuColor) {
this.skuColor = skuColor;
}
}
4.属性枚举
package littlehow.convert.pojo;
/**
* Color
*
* @author littlehow
* @time 2017-05-04 09:21
*/
public enum Color {
BLACK(1),
RED(2),
BLUE(3),
GREEN(4);
public final int value;
Color(int value) {
this.value = value;
}
public static Color valueOf(int value) {
switch (value) {
case 1 : return BLACK;
case 2 : return RED;
case 3 : return BLUE;
case 4 : return GREEN;
default : throw new IllegalArgumentException(value + " is not a enum value");
}
}
}
转换用的dto,当然也可以将dto作为转换源
1.产品dto
package littlehow.convert.dto;
import littlehow.convert.SimpleToStringParent;
import littlehow.convert.pojo.Item;
import java.util.List;
/**
* ProductDto
*
* @author littlehow
* @time 2017-05-04 09:16
*/
public class ProductDto extends SimpleToStringParent {
private Integer productId;
private String generalName;
private String factoryName;
private String unit;
private String specification;
private Integer category;
private List items;
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public String getGeneralName() {
return generalName;
}
public void setGeneralName(String generalName) {
this.generalName = generalName;
}
public String getFactoryName() {
return factoryName;
}
public void setFactoryName(String factoryName) {
this.factoryName = factoryName;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
public String getSpecification() {
return specification;
}
public void setSpecification(String specification) {
this.specification = specification;
}
public List getItems() {
return items;
}
public void setItems(List items) {
this.items = items;
}
public Integer getCategory() {
return category;
}
public void setCategory(Integer category) {
this.category = category;
}
}
2.商品dto
package littlehow.convert.dto;
import littlehow.convert.SimpleToStringParent;
import littlehow.convert.pojo.Sku;
import java.util.Date;
import java.util.List;
/**
* ItemDto
*
* @author littlehow
* @time 2017-05-04 09:16
*/
public class ItemDto extends SimpleToStringParent {
private Integer itemId;
private String itemName;
private Byte status;
private Boolean deleted;
private Date createTime;
private List skus;
public Integer getItemId() {
return itemId;
}
public void setItemId(Integer itemId) {
this.itemId = itemId;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public Byte getStatus() {
return status;
}
public void setStatus(Byte status) {
this.status = status;
}
public Boolean getDeleted() {
return deleted;
}
public void setDeleted(Boolean deleted) {
this.deleted = deleted;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public List getSkus() {
return skus;
}
public void setSkus(List skus) {
this.skus = skus;
}
}
3.skudto
package littlehow.convert.dto;
import littlehow.convert.SimpleToStringParent;
import littlehow.convert.pojo.Color;
/**
* SkuDto
*
* @author littlehow
* @time 2017-05-04 09:16
*/
public class SkuDto extends SimpleToStringParent {
private Long skuId;
private Byte status;
private Boolean deleted;
private Double price;
private Double promoPrice;
private Integer inventory;
private Integer minBuy;
private Integer blockInventory;
private ColorDto skuColor;
public Long getSkuId() {
return skuId;
}
public void setSkuId(Long skuId) {
this.skuId = skuId;
}
public Byte getStatus() {
return status;
}
public void setStatus(Byte status) {
this.status = status;
}
public Boolean getDeleted() {
return deleted;
}
public void setDeleted(Boolean deleted) {
this.deleted = deleted;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Double getPromoPrice() {
return promoPrice;
}
public void setPromoPrice(Double promoPrice) {
this.promoPrice = promoPrice;
}
public Integer getInventory() {
return inventory;
}
public void setInventory(Integer inventory) {
this.inventory = inventory;
}
public Integer getMinBuy() {
return minBuy;
}
public void setMinBuy(Integer minBuy) {
this.minBuy = minBuy;
}
public Integer getBlockInventory() {
return blockInventory;
}
public void setBlockInventory(Integer blockInventory) {
this.blockInventory = blockInventory;
}
public ColorDto getSkuColor() {
return skuColor;
}
public void setSkuColor(ColorDto skuColor) {
this.skuColor = skuColor;
}
}
4.颜色属性
package littlehow.convert.dto;
/**
* ColorDto
*
* @author littlehow
* @time 2017-05-04 09:21
*/
public enum ColorDto {
BLACK(1),
RED(2),
BLUE(3),
GREEN(4);
public final int value;
ColorDto(int value) {
this.value = value;
}
public static ColorDto valueOf(int value) {
switch (value) {
case 1 : return BLACK;
case 2 : return RED;
case 3 : return BLUE;
case 4 : return GREEN;
default : throw new IllegalArgumentException(value + " is not a enum value");
}
}
}
测试类,简单的做了一下输出查看
package littlehow.convert.test;
import littlehow.convert.PojoConvertUtil;
import littlehow.convert.dto.ItemDto;
import littlehow.convert.dto.ProductDto;
import littlehow.convert.dto.SkuDto;
import littlehow.convert.pojo.Color;
import littlehow.convert.pojo.Item;
import littlehow.convert.pojo.Product;
import littlehow.convert.pojo.Sku;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* TransTest
*
* @author littlehow
* @time 2017-05-04 10:44
*/
public class TransTest {
private Product product;
@Before
public void init() {
product = new Product();
product.setCategory(123);
product.setFactoryName("littlehow's shop");
product.setGeneralName("littlehow's product");
product.setProductId(1);
product.setSpecification("16*2u");
product.setUnit("box");
List- items = new ArrayList<>();
for (int i=1; i<=5; i++) {
Item item = new Item();
item.setCreateTime(new Date());
item.setDeleted(i % 3 == 0);
item.setItemId((long) i);
item.setItemName("littlehow's " + i + "th item");
item.setStatus((byte) (i % 4));
List
skus = new ArrayList<>();
for (int j=1; j<=i; j++) {
Sku sku = new Sku();
sku.setSkuId((long)(j * (i + 5) * 3));
sku.setStatus((byte) 1);
sku.setDeleted(false);
sku.setBlockInventory(5);
sku.setInventory(j * 100);
sku.setMinBuy(j * 5);
sku.setPrice(Double.valueOf(j * 103));
sku.setPromoPrice(Double.valueOf(j * 101));
sku.setSkuColor(Color.valueOf(j % 4 + 1));
skus.add(sku);
}
item.setSkus(skus);
items.add(item);
}
product.setItems(items);
}
@Test
public void test() {
System.out.println(product);//正常输出
System.out.println("========================");
ProductDto productDto = PojoConvertUtil.convertPojo(product, ProductDto.class);
System.out.println(productDto);//正常输出,证明转换正常
System.out.println("=========================");
List- items = product.getItems();
List
itemDtos = PojoConvertUtil.convertPojos(items, ItemDto.class);
System.out.println(itemDtos);//正常输出,数组转换成功
}
@Test
public void test1() {
Sku sku = product.getItems().get(0).getSkus().get(0);
System.out.println(sku);//正常输出
System.out.println("=========================");
SkuDto skuDto = PojoConvertUtil.convertPojo(sku, SkuDto.class);
System.out.println(skuDto);
}
}
能快速完成基础类之间的互转
工作笔记
littlehow 于2017/5/4