世界上并没有完美的程序,但是我们并不因此而沮丧,因为写程序就是一个不断追求完美的过程。
我们在使用Entity做set时总是得通过entity.setXXX()这种形式,如果是通过构建器生成,得写好多多余的代码,才有new Entity().setXXX().setXXX().build()。
这里参考mybatis-plus的LambdaQueryWrapper,利用Lambda表达式和反射编写了一个通用的实体类生成工具并且可附带条件语句。
效果展示:
package com.test.demo.entitybuilder;
import java.util.Date;
/**
* @author hbw
*/
public class TestC {
public static void main(String[] args) {
String id = "1";
String name = "hello";
int age = 13;
Date date = new Date();
test(id, name, age, date);
}
// 实体生成工具类测试
private static void test(String id, String name, Integer age, Date date) {
User user = EntityBuilder.create(User.class)
.set(User::getId, id)
.set(User::getName, name, (null != name && name.length() > 1))
.set(User::getAge, age, age > 11)
.set(User::getDate, date)
.build();
System.out.println("user : " + user);
}
static class User {
private String id;
private String name;
private Integer age;
private Date date;
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 Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", date=" + date +
'}';
}
}
}
结果
com.gpower.modules.user.entity.User@2f943d71[password=pwd,createTime=Wed Mar 10 15:19:25 CST 2021,id=1,name=hello]
源码如下所示
package com.test.demo.entitybuilder;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.function.Function;
/**
* @author hbw
*/
public final class EntityBuilder<E> {
private static final String SET = "set";
private static final String GET = "get";
private E o;
private EntityBuilder(Class<E> clazz) {
try {
this.o = clazz.newInstance();
} catch (Exception e) {e.printStackTrace();}
}
public static <M> EntityBuilder<M> create(Class<M> c) {
return new EntityBuilder<>(c);
}
public <T, R> EntityBuilder<E> set(SFunc<T, R> func, Object arg, boolean setCondition) {
if (!setCondition) {
return this;
}
return set(func, arg);
}
public <T, R> EntityBuilder<E> set(SFunc<T, R> func, Object arg) {
SerializedLambda serializedLambda = SerializedLambda.resolve(func);
String methodName = serializedLambda.getImplMethodName();
invokeMethod(methodName, arg);
return this;
}
public E build() {
return o;
}
// -------------------------------------------------------------------------------
private void invokeMethod(String methodName, Object arg) {
try {
if (null != methodName && methodName.startsWith(GET)) {
methodName = SET + methodName.substring(3);
Class<?> clazz = o.getClass();
Class<?>[] paramClasses = getParamClasses(methodName, clazz);
Method method = clazz.getMethod(methodName, paramClasses);
method.invoke(o, arg);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private Class<?>[] getParamClasses(String methodName, Class<?> clazz) {
Method[] methods = clazz.getMethods();
Class<?>[] paramClasses = null;
for (Method method : methods) {
String meName = method.getName();
Class<?>[] classes = method.getParameterTypes();
if (methodName.equals(meName)) {
paramClasses = classes;
break;
}
}
return paramClasses;
}
@FunctionalInterface
public interface SFunc<T, R> extends Function<T, R>, Serializable {
}
}
package com.test.demo.entitybuilder;
import java.io.*;
/**
* @author hbw
*/
public class SerializedLambda implements Serializable {
private static final long serialVersionUID = 8025925345765570181L;
private String implMethodName;
public static SerializedLambda resolve(EntityBuilder.SFunc<?, ?> lambda) {
SerializedLambda serializedLambda = null;
ObjectInputStream objIn = null;
try {
objIn = new ObjectInputStream(new ByteArrayInputStream(serialize(lambda))) {
protected Class<?> resolveClass(ObjectStreamClass objectStreamClass)
throws IOException, ClassNotFoundException {
Class<?> clazz = super.resolveClass(objectStreamClass);
return clazz == java.lang.invoke.SerializedLambda.class ?
SerializedLambda.class : clazz;
}
};
serializedLambda = (SerializedLambda) objIn.readObject();
} catch (Exception e) {e.printStackTrace();} finally {
try { objIn.close(); } catch (Exception e) {}
}
return serializedLambda;
}
public String getImplMethodName() {
return this.implMethodName;
}
public static byte[] serialize(Object object) {
if (object == null) {
return null;
} else {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
try {
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.flush();
} catch (IOException var3) {
throw new IllegalArgumentException(
"Failed to serialize object of type: "
+ object.getClass(), var3);
}
return baos.toByteArray();
}
}
}