分享dataBean不同导致的方法传参问题(以需求做讲解)
基础数据
A模块定义的BeanA
package com.fspdfcy;
import java.io.Serializable;
import java.util.Objects;
/**
* @author fsp
* @version 1.0
* @date 2022/11/11
* @since test
*/
public class BeanA implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String name;
private String type;
private int count;
// 独有属性,区分BeanB
private String ofOwn1;
private String ofOwn2;
private String ofOwn3;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String getOfOwn1() {
return ofOwn1;
}
public void setOfOwn1(String ofOwn1) {
this.ofOwn1 = ofOwn1;
}
public String getOfOwn2() {
return ofOwn2;
}
public void setOfOwn2(String ofOwn2) {
this.ofOwn2 = ofOwn2;
}
public String getOfOwn3() {
return ofOwn3;
}
public void setOfOwn3(String ofOwn3) {
this.ofOwn3 = ofOwn3;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BeanA beanA = (BeanA) o;
return count == beanA.count && Objects.equals(id, beanA.id) && Objects.equals(name, beanA.name) && Objects.equals(type, beanA.type) && Objects.equals(ofOwn1, beanA.ofOwn1) && Objects.equals(ofOwn2, beanA.ofOwn2) && Objects.equals(ofOwn3, beanA.ofOwn3);
}
@Override
public int hashCode() {
return Objects.hash(id, name, type, count, ofOwn1, ofOwn2, ofOwn3);
}
@Override
public String toString() {
return "BeanA{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", type='" + type + '\'' +
", count=" + count +
", ofOwn1='" + ofOwn1 + '\'' +
", ofOwn2='" + ofOwn2 + '\'' +
", ofOwn3='" + ofOwn3 + '\'' +
'}';
}
}
B模块定义的BeanB
package com.fspdfcy;
import java.util.Objects;
/**
* @author fsp
* @version 1.0
* @date 2022/11/11
* @since test
*/
public class BeanB {
private static final long serialVersionUID = 1L;
private String id;
private String name;
private String type;
private int count;
// 独有属性,区分BeanA
private String ofOwn4;
private String ofOwn5;
private String ofOwn6;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String getOfOwn4() {
return ofOwn4;
}
public void setOfOwn4(String ofOwn4) {
this.ofOwn4 = ofOwn4;
}
public String getOfOwn5() {
return ofOwn5;
}
public void setOfOwn5(String ofOwn5) {
this.ofOwn5 = ofOwn5;
}
public String getOfOwn6() {
return ofOwn6;
}
public void setOfOwn6(String ofOwn6) {
this.ofOwn6 = ofOwn6;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BeanB beanB = (BeanB) o;
return count == beanB.count && Objects.equals(id, beanB.id) && Objects.equals(name, beanB.name) && Objects.equals(type, beanB.type) && Objects.equals(ofOwn4, beanB.ofOwn4) && Objects.equals(ofOwn5, beanB.ofOwn5) && Objects.equals(ofOwn6, beanB.ofOwn6);
}
@Override
public int hashCode() {
return Objects.hash(id, name, type, count, ofOwn4, ofOwn5, ofOwn6);
}
@Override
public String toString() {
return "BeanB{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", type='" + type + '\'' +
", count=" + count +
", ofOwn4='" + ofOwn4 + '\'' +
", ofOwn5='" + ofOwn5 + '\'' +
", ofOwn6='" + ofOwn6 + '\'' +
'}';
}
}
业务需求:传入BeanA集合或BeanB集合,根据name和type(都有这两个属性)根据业务逻辑结束后填入count字段,但私有属性不能丢失。
一开始的思路:定义BeanC,将BeanA和BeanB的所有属性加载BeanC中,然后方法定义入参BeanC,在调用服务的时候使用BeanUtils将BeanA和BeanB转换为BeanC(理论可行,但未去实现)
问题在于,如果其他模块定义了其他bean,但都要调用这个服务的时候这就是地狱了,不具备通用性。
解决方案
方法接收List<T>
list,将list转化为map,再根据通用属性处理业务逻辑(使用map.get(“name”)),处理完成写入count(使用map.put(“count”,22)),最后将处理完成的数据转换回去并返回,这样不会导致数据的丢失,且具备通用性。
定义转换类 ConvertUtil (当然也可以使用第三方工具类)
package com.fspdfcy;
import com.alibaba.fastjson.JSON;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* @author fsp
* @version 1.0
* @date 2022/11/11
* @since test
*/
public class ConvertUtil {
private ConvertUtil() {
throw new RuntimeException("工具类不能实例化");
}
public static <T> void makeMapToObject(Map<String, Object> map, T obj) {
Objects.requireNonNull(map);
Class<?> aClass = obj.getClass();
for (Map.Entry<String, Object> entry : map.entrySet()) {
String filedName = entry.getKey();
String methodName = "set" + filedName.toUpperCase().charAt(0) + filedName.substring(1);
try {
if (entry.getValue() != null) {
Method setMethod = aClass.getDeclaredMethod(methodName, entry.getValue().getClass());
setMethod.invoke(obj, entry.getValue());
}
} catch (Exception e) {
// e.printStackTrace(); // 正常异常,无需打印
}
}
}
public static <T> T makeMapToObject(Map<String, Object> map, Class<T> clazz) {
Objects.requireNonNull(map);
T obj = null;
try {
obj = clazz.newInstance();
for (Map.Entry<String, Object> entry : map.entrySet()) {
String filedName = entry.getKey();
String methodName = "set" + filedName.toUpperCase().charAt(0) + filedName.substring(1);
try {
if (entry.getValue() != null) {
Method setMethod = clazz.getDeclaredMethod(methodName, entry.getValue().getClass());
setMethod.invoke(obj, entry.getValue());
}
} catch (Exception e) {
// e.printStackTrace(); // 正常异常,无需打印
}
}
} catch (Exception e) {
e.printStackTrace(); // 正常异常,无需打印
}
return obj;
}
public static <T> List<T> makeMapListTpObjectList(List<Map<String, Object>> mapList, Class<T> clazz) {
Objects.requireNonNull(mapList);
List<T> list = new ArrayList<>(mapList.size());
mapList.forEach(map -> {
list.add(makeMapToObject(map, clazz));
});
return list;
}
@SuppressWarnings("unchecked")
public static Map<String, Object> makeObjectMap(Object obj) {
return (Map<String, Object>) JSON.toJSON(obj);
}
@SuppressWarnings("unchecked")
public static <T> List<Map<String, Object>> makeObjectListToMapList(List<T> objectList) {
return (List<Map<String, Object>>) JSON.toJSON(objectList);
}
}
服务接口
package com.fspdfcy.service;
import java.util.List;
/**
* @author fsp
* @version 1.0
* @date 2022/11/11
* @since test
*/
public interface Service {
<T> List<T> doSomething(List<T> list);
}
服务实现
package com.fspdfcy.service.impl;
import com.fspdfcy.ConvertUtil;
import com.fspdfcy.service.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author fsp
* @version 1.0
* @date 2022/11/11
* @since test
*/
public class ServiceImpl implements Service {
@Override
@SuppressWarnings("unchecked")
public <T> List<T> doSomething(List<T> list) {
// 为空直接返回
if (list == null || list.size() == 0) {
return new ArrayList<>();
}
List<Map<String, Object>> mapList = ConvertUtil.makeObjectListToMapList(list);
// 业务逻辑xxx
String name = mapList.get(0).get("name").toString();
String type = mapList.get(0).get("type").toString();
// 填入count
mapList.forEach(map -> {
map.put("count", 2);
});
return (List<T>) ConvertUtil.makeMapListToObjectList(mapList, list.get(0).getClass());
}
}
测试
package com.fspdfcy.service.impl;
import com.fspdfcy.ConvertUtil;
import com.fspdfcy.service.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author fsp
* @version 1.0
* @date 2022/11/11
* @since test
*/
public class ServiceImpl implements Service {
@Override
@SuppressWarnings("unchecked")
public <T> List<T> doSomething(List<T> list) {
// 为空直接返回
if (list == null || list.size() == 0) {
return new ArrayList<>();
}
List<Map<String, Object>> mapList = ConvertUtil.makeObjectListToMapList(list);
// 业务逻辑xxx
String name = mapList.get(0).get("name").toString();
String type = mapList.get(0).get("type").toString();
// 填入count
mapList.forEach(map -> {
map.put("count", 2);
});
return (List<T>) ConvertUtil.makeMapListToObjectList(mapList, list.get(0).getClass());
}
}
结果
[BeanA{id='a1', name='a1', type='a1', count=0, ofOwn1='a1', ofOwn2='a1', ofOwn3='a1'}, BeanA{id='a2', name='a2', type='a2', count=0, ofOwn1='a2', ofOwn2='a2', ofOwn3='a2'}, BeanA{id='a3', name='a3', type='a3', count=0, ofOwn1='a3', ofOwn2='a3', ofOwn3='a3'}]
[BeanB{id='b1', name='b1', type='b1', count=0, ofOwn4='b1', ofOwn5='b1', ofOwn6='b1'}, BeanB{id='b2', name='b2', type='b2', count=0, ofOwn4='b2', ofOwn5='b2', ofOwn6='b2'}, BeanB{id='b3', name='b3', type='b3', count=0, ofOwn4='b3', ofOwn5='b3', ofOwn6='b3'}]
可能有仔细的人已经发现问题了,就是count没有改变,对,这就是我要抛出的重要点,dataBean需要全部都是引用类型,引用类型,引用类型。因为在转为为mapList的时候自动装箱了,然后在转化为beanList的时候其实是报错找不到方法com.fspdfcy.BeanB.setCount(java.lang.Integer)
所以解决办法就是将BeanA和BeanB所有的基本数据类型转换为包装类,就能解决问题了。
附上修改后的结果
[BeanA{id='a1', name='a1', type='a1', count=2, ofOwn1='a1', ofOwn2='a1', ofOwn3='a1'}, BeanA{id='a2', name='a2', type='a2', count=2, ofOwn1='a2', ofOwn2='a2', ofOwn3='a2'}, BeanA{id='a3', name='a3', type='a3', count=2, ofOwn1='a3', ofOwn2='a3', ofOwn3='a3'}]
[BeanB{id='b1', name='b1', type='b1', count=2, ofOwn4='b1', ofOwn5='b1', ofOwn6='b1'}, BeanB{id='b2', name='b2', type='b2', count=2, ofOwn4='b2', ofOwn5='b2', ofOwn6='b2'}, BeanB{id='b3', name='b3', type='b3', count=2, ofOwn4='b3', ofOwn5='b3', ofOwn6='b3'}]
至此,完美解决问题