Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

新增处理record类的相关功能 #88

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bean-searcher/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
<version>4.2.4</version>
</parent>

<properties>
<java.version>17</java.version>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

得兼容 Java 8

</properties>


<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import cn.zhxu.bs.*;
import cn.zhxu.bs.FieldConvertor.BFieldConvertor;

import java.lang.reflect.Constructor;
import java.lang.reflect.RecordComponent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
Expand All @@ -11,88 +13,116 @@

/**
* 默认查询结果解析器
*
*
* @author Troy.Zhou @ 2017-03-20
*/
public class DefaultBeanReflector implements BeanReflector {

private List<BFieldConvertor> convertors;
private List<BFieldConvertor> convertors;

public DefaultBeanReflector() {
this(new ArrayList<>());
}

public DefaultBeanReflector(List<BFieldConvertor> convertors) {
this.convertors = convertors;
}

@Override
public <T> T reflect(BeanMeta<T> beanMeta, Collection<FieldMeta> fetchFields, Function<String, Object> valueGetter) {
Class<T> beanClass = beanMeta.getBeanClass();
T bean = newInstance(beanClass);
for (FieldMeta meta : fetchFields) {
Object value = valueGetter.apply(meta.getDbAlias());
try {
value = convert(meta, value);
} catch (Exception e) {
throw new SearchException(
"The type of [" + beanClass + "#" + meta.getName() + "] is mismatch with it's database table field type", e);
}
if (value != null) {
try {
meta.getField().set(bean, value);
} catch (ReflectiveOperationException e) {
throw new SearchException(
"A exception occurred when setting value to [" + beanClass.getName() + "#" + meta.getName() + "], please check whether it's setter is correct.", e);
}
}
}
return bean;
}
public DefaultBeanReflector() {
this(new ArrayList<>());
}

protected Object convert(FieldMeta meta, Object value) {
if (value == null) {
return null;
}
Class<?> valueType = value.getClass();
Class<?> targetType = meta.getType();
if (targetType.isAssignableFrom(valueType)) {
// 如果 targetType 是 valueType 的父类,则直接返回
return value;
}
for (FieldConvertor convertor: convertors) {
if (convertor.supports(meta, valueType)) {
return convertor.convert(meta, value);
}
}
throw new SearchException("Can not convert " + valueType + " to " + targetType + " for " + meta.getBeanMeta().getBeanClass() +
"#" + meta.getName() + ", please check the field type, or you can add a BFieldConvertor for it.");
}
public DefaultBeanReflector(List<BFieldConvertor> convertors) {
this.convertors = convertors;
}

protected <T> T newInstance(Class<T> beanClass) {
try {
return beanClass.getDeclaredConstructor().newInstance();
} catch (NoSuchMethodException e) {
throw new SearchException("Can not instantiate [" + beanClass.getName() +
"], please check whether there is a constructor without parameters on it.", e);
} catch (Exception e) {
throw new SearchException("Can not instantiate [" + beanClass.getName() +
"], please check whether the constructor without parameters can be invoked without errors.", e);
}
}
@Override
public <T> T reflect(BeanMeta<T> beanMeta, Collection<FieldMeta> fetchFields, Function<String, Object> valueGetter) {
Class<T> beanClass = beanMeta.getBeanClass();
if (beanClass.isRecord()) {
ArrayList<Class<?>> fieldClassArrayList = new ArrayList<>();
ArrayList<Object> valueArrayList = new ArrayList<>();
RecordComponent[] recordComponentArray = beanClass.getRecordComponents();
for (RecordComponent recordComponent : recordComponentArray) {
fieldClassArrayList.add(recordComponent.getType());
for (FieldMeta meta : fetchFields) {
if (Objects.equals(meta.getName(), recordComponent.getName())) {
Object value = valueGetter.apply(meta.getDbAlias());
try {
value = convert(meta, value);
} catch (Exception e) {
throw new SearchException(
"The type of [" + beanClass + "#" + meta.getName() + "] is mismatch with it's database table field type", e);
}
valueArrayList.add(value);//使用record类的构造方法需要保证每个值与属性全部对应,不能将null值去掉
}
}
}
try {
Constructor<T> declaredConstructor = beanClass.getDeclaredConstructor(fieldClassArrayList.toArray(Class<?>[]::new));
return declaredConstructor.newInstance(valueArrayList.toArray());
} catch (ReflectiveOperationException e) {
throw new SearchException(
"A exception occurred when build record constructor , please check target record " + beanClass);
}
}

public List<BFieldConvertor> getConvertors() {
return convertors;
}
T bean = newInstance(beanClass);
for (FieldMeta meta : fetchFields) {
Object value = valueGetter.apply(meta.getDbAlias());
try {
value = convert(meta, value);
} catch (Exception e) {
throw new SearchException(
"The type of [" + beanClass + "#" + meta.getName() + "] is mismatch with it's database table field type", e);
}
if (value != null) {
try {
meta.getField().set(bean, value);
} catch (ReflectiveOperationException e) {
throw new SearchException(
"A exception occurred when setting value to [" + beanClass.getName() + "#" + meta.getName() + "], please check whether it's setter is correct.", e);
}
}
}
return bean;
}

public void setConvertors(List<BFieldConvertor> convertors) {
this.convertors = Objects.requireNonNull(convertors);
}
protected Object convert(FieldMeta meta, Object value) {
if (value == null) {
return null;
}
Class<?> valueType = value.getClass();
Class<?> targetType = meta.getType();
if (targetType.isAssignableFrom(valueType)) {
// 如果 targetType 是 valueType 的父类,则直接返回
return value;
}
for (FieldConvertor convertor : convertors) {
if (convertor.supports(meta, valueType)) {
return convertor.convert(meta, value);
}
}
throw new SearchException("Can not convert " + valueType + " to " + targetType + " for " + meta.getBeanMeta().getBeanClass() +
"#" + meta.getName() + ", please check the field type, or you can add a BFieldConvertor for it.");
}

public void addConvertor(BFieldConvertor convertor) {
if (convertor != null) {
convertors.add(convertor);
}
}
protected <T> T newInstance(Class<T> beanClass) {
try {
return beanClass.getDeclaredConstructor().newInstance();
} catch (NoSuchMethodException e) {
throw new SearchException("Can not instantiate [" + beanClass.getName() +
"], please check whether there is a constructor without parameters on it.", e);
} catch (Exception e) {
throw new SearchException("Can not instantiate [" + beanClass.getName() +
"], please check whether the constructor without parameters can be invoked without errors.", e);
}
}

public List<BFieldConvertor> getConvertors() {
return convertors;
}

public void setConvertors(List<BFieldConvertor> convertors) {
this.convertors = Objects.requireNonNull(convertors);
}

public void addConvertor(BFieldConvertor convertor) {
if (convertor != null) {
convertors.add(convertor);
}
}

}
10 changes: 6 additions & 4 deletions bean-searcher/src/main/java/cn/zhxu/bs/util/FieldFns.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,21 @@
* <pre>{@code
* String name = FieldFns.name(User::getName);
* }</pre>
* @since v3.8.1
*
* @author Troy.Zhou @ 2017-03-20
* @since v3.8.1
*/
public class FieldFns {

@FunctionalInterface
public interface FieldFn<T, R> extends Function<T, R>, Serializable { }
public interface FieldFn<T, R> extends Function<T, R>, Serializable {
}

private static final Map<FieldFn<?, ?>, String> cache = new ConcurrentHashMap<>();

/**
* @param fieldFn 方法引用
* @param <T> 泛型
* @param <T> 泛型
* @return 该方法对应的属性名
*/
public static <T> String name(FieldFn<T, ?> fieldFn) {
Expand Down Expand Up @@ -54,7 +56,7 @@ public static <T> String name(FieldFn<T, ?> fieldFn) {
cache.put(fieldFn, name);
return name;
}
throw new IllegalStateException("Can not resolve the name of method: " + methodName);
return methodName;
} catch (ReflectiveOperationException e) {
throw new IllegalStateException("Can not resolve the name of " + fieldFn, e);
}
Expand Down
73 changes: 73 additions & 0 deletions bean-searcher/src/test/java/cn/zhxu/bs/BeanRefactorTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,57 @@ private void assertEquals(Object expect, Object value) {

}

public record TestRecord(
@DbField(alias = "id")
long id,
@DbField(alias = "name")
String name,
@DbField(alias = "age")
int age,
@DbField(alias = "dateCreated")
Date dateCreated
) {


@Override
public String toString() {
return "id=" + id +
", name='" + name + '\'' +
", age=" + age +
", dateCreated=" + format.format(dateCreated);
}

public void assertEqual(Map<String, Object> values) {
assertEquals(values.get("id"), id);
assertEquals(values.get("name"), name);
assertEquals(values.get("age"), age);
assertEquals(values.get("dateCreated"), dateCreated);
}

private void assertEquals(Object expect, Object value) {
if (expect instanceof String) {
Assert.assertEquals(expect, String.valueOf(value));
} else if (expect instanceof Number && value instanceof Number) {
Assert.assertEquals(((Number) expect).longValue(), ((Number) value).longValue());
} else if (value instanceof Date) {
if (expect instanceof Date) {
Assert.assertEquals(expect, value);
}
if (expect instanceof LocalDateTime) {
Assert.assertEquals(((LocalDateTime) expect).getYear(), ((Date) value).getYear() + 1900);
Assert.assertEquals(((LocalDateTime) expect).getMonth().getValue(), ((Date) value).getMonth() + 1);
Assert.assertEquals(((LocalDateTime) expect).getDayOfMonth(), ((Date) value).getDate());
Assert.assertEquals(((LocalDateTime) expect).getHour(), ((Date) value).getHours());
Assert.assertEquals(((LocalDateTime) expect).getMinute(), ((Date) value).getMinutes());
Assert.assertEquals(((LocalDateTime) expect).getSecond(), ((Date) value).getSeconds());
}
} else {
Assert.assertEquals(expect, value);
}
}

}

final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

final MetaResolver metaResolver = new DefaultMetaResolver();
Expand Down Expand Up @@ -98,5 +149,27 @@ public void test() {
System.out.println("BeanRefactorTests OK!");
}

@Test
public void testRecord() {
BeanMeta<TestRecord> beanMeta = metaResolver.resolve(TestRecord.class);
Collection<FieldMeta> fieldSet = beanMeta.getFieldMetas();

Map<String, Object> values1 = new HashMap<>();
values1.put("id", 1);
values1.put("name", "Tom");
values1.put("age", 20);
values1.put("dateCreated", new Date());

beanReflector.reflect(beanMeta, fieldSet, values1::get).assertEqual(values1);

Map<String, Object> values2 = new HashMap<>();
values2.put("id", "100");
values2.put("name", "Tom");
values2.put("age", 20L);
values2.put("dateCreated", LocalDateTime.now());

beanReflector.reflect(beanMeta, fieldSet, values2::get).assertEqual(values2);
System.out.println("RecordRefactorTests OK!");
}

}
Loading