org.nervousync.utils.BeanUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of utils-jdk11 Show documentation
Show all versions of utils-jdk11 Show documentation
Java utility collections, development by Nervousync Studio (NSYC)
/*
* Licensed to the Nervousync Studio (NSYC) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.nervousync.utils;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import org.nervousync.annotations.beans.BeanProperty;
import org.nervousync.beans.converter.Adapter;
import org.nervousync.beans.converter.impl.beans.AbstractBeanAdapter;
import org.nervousync.commons.Globals;
import org.nervousync.enumerations.beans.DataFlow;
/**
* JavaBean Utilities
*
* Current utilities implements features:
* Copy object fields value from source object to target object based field name
* Copy object fields value from source object array to target object based annotation: BeanProperty
* Copy object fields value from source object to target object arrays based annotation: BeanProperty
*
* JavaBean工具集
*
* 此工具集实现以下功能:
* 根据属性名称从源数据对象复制数据到目标数据对象
* 根据BeanProperty注解从源数据对象数组复制数据到目标数据对象
* 根据BeanProperty注解从源数据对象复制数据到目标数据对象数组
*
*
* @author Steven Wee [email protected]
* @version $Revision: 1.2.0 $ $Date: Jun 25, 2015 14:55:15 $
*/
public final class BeanUtils {
/**
* Logger instance
* 日志实例
*/
private static final LoggerUtils.Logger LOGGER = LoggerUtils.getLogger(BeanUtils.class);
/**
* Registered JavaBean mappings
* 已注册的JavaBean映射
*/
private static final Map BEAN_CONFIG_MAP = new HashMap<>();
/**
* Private constructor for BeanUtils
* JavaBean工具集的私有构造函数
*/
private BeanUtils() {
}
/**
* Remove registered JavaBean class
* 移除已注册的JavaBean类映射
*
* @param classes Want removed JavaBean class array
* 需要移除的JavaBean类数组
*/
public static void removeBeanConfig(final Class>... classes) {
Arrays.asList(classes).forEach(clazz -> BEAN_CONFIG_MAP.remove(ClassUtils.originalClassName(clazz)));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Register_Bean_Config_Count_Debug", BEAN_CONFIG_MAP.size());
}
}
/**
* Copy the map values into the target JavaBean instance
* Data mapping to JavaBean field identified by map key
* 复制Map中的值到目标JavaBean实例
* 数据使用Map的键值映射到JavaBean属性
*
* @param originalMap Original data map
* 来源数据Map
* @param targetObject Target JavaBean instance
* 目标JavaBean实例
*/
public static void copyProperties(final Map originalMap, final Object targetObject) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Data_Map_Debug",
StringUtils.objectToString(originalMap, StringUtils.StringType.JSON, Boolean.TRUE));
}
checkRegister(targetObject.getClass());
Optional.ofNullable(BEAN_CONFIG_MAP.get(ClassUtils.originalClassName(targetObject.getClass())))
.ifPresent(beanMapping -> beanMapping.copyData(targetObject, originalMap));
}
/**
* Copy the property values of the given source bean arrays into the target bean
* Data mapping by field annotated with org.nervousync.annotations.beans.BeanProperty
* 从给定的JavaBean对象数组复制映射的属性值到目标对象
* 数据映射配置于使用org.nervousync.annotations.beans.BeanProperty注解的属性
*
* @param targetObject Target JavaBean instance
* 目标JavaBean实例
* @param originalObjects Original JavaBean instance array
* 数据源JavaBean实例数组
*/
public static void copyFrom(final Object targetObject, final Object... originalObjects) {
if (targetObject == null || originalObjects.length == 0) {
return;
}
checkRegister(targetObject.getClass());
Optional.ofNullable(BEAN_CONFIG_MAP.get(ClassUtils.originalClassName(targetObject.getClass())))
.ifPresent(beanMapping -> beanMapping.copyData(DataFlow.IN, targetObject, originalObjects));
}
/**
* Copy the property values into the given target JavaBean instance arrays
* Data mapping by field annotated with org.nervousync.annotations.beans.Mappings
* 从源对象复制属性值到给定的JavaBean对象数组
* 数据映射配置于使用org.nervousync.annotations.beans.Mappings注解的属性
*
* @param originalObject Original JavaBean instance
* 数据源JavaBean实例
* @param targetObjects Target JavaBean instance array
* 目标JavaBean实例数组
*/
public static void copyTo(final Object originalObject, final Object... targetObjects) {
if (originalObject == null || targetObjects.length == 0) {
return;
}
checkRegister(originalObject.getClass());
Optional.ofNullable(BEAN_CONFIG_MAP.get(ClassUtils.originalClassName(originalObject.getClass())))
.ifPresent(beanMapping -> beanMapping.copyData(DataFlow.OUT, originalObject, targetObjects));
}
/**
* Check and register JavaBean mapping configs
* If given JavaBean class instance not registered, generate BeanMapping instance and register the given JavaBean class mapping configure
* 检查并注册JavaBean映射配置
* 如果给定的JavaBean类没有注册映射配置,则生成映射配置对象,并执行注册
*
* @param clazz Given JavaBean class instance
* 给定的JavaBean类对象
*/
private static void checkRegister(final Class> clazz) {
Optional.of(ClassUtils.originalClassName(clazz))
.filter(StringUtils::notBlank)
.filter(className -> !BEAN_CONFIG_MAP.containsKey(className))
.ifPresent(className -> BEAN_CONFIG_MAP.put(className, new BeanMapping(clazz)));
}
/**
* JavaBean mapping configure define
* Private inner class for define JavaBean mapping configure
* JavaBean映射配置定义
* 定义JavaBean映射配置的私有内部类
*/
private static final class BeanMapping {
/**
* JavaBean field mapping configure list
* JavaBean属性映射配置列表
*/
private final List fieldMappings;
/**
* Constructor for parse given JavaBean class instance and generate BeanMapping instance
* 构造方法用于解析给定的JavaBean类对象,并生成BeanMapping对象
*
* @param beanClass Given JavaBean class instance
* 给定的JavaBean类对象
*/
BeanMapping(final Class> beanClass) {
this.fieldMappings = new ArrayList<>();
ReflectionUtils.getAllDeclaredFields(beanClass, Boolean.TRUE)
.forEach(field -> this.fieldMappings.add(new FieldMapping(field)));
}
/**
* Copy property value from data map
* 从数据Map复制属性数据
*
* @param targetObject Target JavaBean instance
* 目标JavaBean实例
* @param originalMap Original data map
* 来源数据Map
*/
void copyData(final Object targetObject, final Map originalMap) {
this.fieldMappings.forEach(fieldMapping -> fieldMapping.copyData(targetObject, originalMap));
}
/**
* Copy the property values between the JavaBean instance and JavaBean instance arrays
* 在JavaBean对象实例和JavaBean对象实例数组间复制数据
*
* @see org.nervousync.enumerations.beans.DataFlow
* @param dataFlow Data flow, IN
from arrays to object, OUT
from object to arrays
* 数据流向<,IN
从实例数组复制数据到实例对象,OUT
从实例对象复制数据到实例数组/span>
* @param object JavaBean instance
* JavaBean实例
* @param objects JavaBean instance array
* JavaBean实例数组
*/
void copyData(final DataFlow dataFlow, final Object object, final Object... objects) {
this.fieldMappings.forEach(fieldMapping -> fieldMapping.copyData(dataFlow, object, objects));
}
}
/**
* JavaBean field mapping configure define
* Private inner class for define JavaBean field mapping configure
* JavaBean属性映射配置定义
* 定义JavaBean属性映射配置的私有内部类
*/
private static final class FieldMapping {
/**
* JavaBean field name
* JavaBean属性名
*/
private final String fieldName;
/**
* JavaBean field type class
* JavaBean属性数据类型
*/
private final Class> fieldType;
/**
* JavaBean field data mapping configure
* JavaBean属性数据映射配置
*/
private final List propertyMappings;
/**
* Constructor for parse given JavaBean field instance and generate FieldMapping instance
* 构造方法用于解析给定的JavaBean属性对象,并生成FieldMapping对象
*
* @param field JavaBean field instance
* JavaBean类属性对象
*/
FieldMapping(final Field field) {
this.fieldName = field.getName();
this.fieldType = field.getType();
this.propertyMappings = new ArrayList<>();
Arrays.asList(field.getAnnotationsByType(BeanProperty.class)).forEach(this::registerProperty);
this.propertyMappings.sort((o1, o2) -> o2.compare(o1));
}
/**
* Copy property value from data map
* 从数据Map复制属性数据
*
* @param targetObject Target JavaBean instance
* 目标JavaBean实例
* @param originalMap Original data map
* 来源数据Map
*/
void copyData(final Object targetObject, final Map originalMap) {
if (originalMap == null || originalMap.isEmpty()) {
return;
}
Optional.ofNullable(originalMap.get(this.fieldName))
.map(fieldValue ->
this.propertyMappings.stream()
.filter(propertyMapping ->
DataFlow.IN.equals(propertyMapping.dataFlow)
&& Map.class.equals(propertyMapping.beanClass))
.findFirst()
.map(propertyMapping ->
propertyMapping.convertData(fieldValue, this.fieldType))
.orElse(fieldValue))
.ifPresent(fieldValue -> ReflectionUtils.setField(this.fieldName, targetObject, fieldValue));
}
/**
* Copy the property values between the JavaBean instance and JavaBean instance arrays
* 在JavaBean对象实例和JavaBean对象实例数组间复制数据
*
* @param dataFlow Data flow, IN
from arrays to object, OUT
from object to arrays
* 数据流向<,IN
从实例数组复制数据到实例对象,OUT
从实例对象复制数据到实例数组/span>
* @see org.nervousync.enumerations.beans.DataFlow
* @param object JavaBean instance
* JavaBean实例
* @param objects JavaBean instance array
* JavaBean实例数组
*/
void copyData(final DataFlow dataFlow, final Object object, final Object... objects) {
if (object == null || objects == null || objects.length == 0) {
return;
}
final AtomicInteger priority = new AtomicInteger(Globals.DEFAULT_VALUE_INT);
if (this.propertyMappings.isEmpty()) {
switch (dataFlow) {
case IN:
Arrays.asList(objects).forEach(obj -> copyProperties(obj, object));
break;
case OUT:
Arrays.asList(objects).forEach(obj -> copyProperties(object, obj));
break;
}
} else {
this.propertyMappings.stream()
.filter(propertyMapping -> propertyMapping.getDataFlow().equals(dataFlow))
.forEach(propertyMapping -> {
if (propertyMapping.copyData(priority.get(), this.fieldName, this.fieldType, object, objects)) {
priority.set(propertyMapping.getSortCode());
}
});
}
}
/**
* Copy the property values from the source object to the target object, based field name
* 从源数据对象复制数据到目标对象,复制依据属性名称
*
* @param sourceObject Source object instance
* 源数据对象
* @param targetObject Target object instance
* 目标数据对象
*/
void copyProperties(final Object sourceObject, final Object targetObject) {
ReflectionUtils.getAllDeclaredFields(sourceObject.getClass(), Boolean.TRUE)
.forEach(field -> Optional.ofNullable(ReflectionUtils.getFieldValue(field, sourceObject))
.ifPresent(fieldValue ->
ReflectionUtils.setField(field.getName(), targetObject, fieldValue)));
}
/**
* Register BeanProperty annotation who was annotated at field
* 注册注解在属性上的BeanProperty注解
*
* @param beanProperty Annotation instance of BeanProperty
* BeanProperty注解实例
*/
private void registerProperty(final BeanProperty beanProperty) {
if (this.propertyMappings.stream().anyMatch(propertyMapping -> propertyMapping.exists(beanProperty))) {
LOGGER.warn("JavaBean_Property_Mapping_Existed_Warn",
beanProperty.beanClass(), beanProperty.targetField());
}
if (Map.class.equals(beanProperty.beanClass())) {
this.propertyMappings.add(new PropertyMapping(beanProperty));
return;
}
Optional.ofNullable(ReflectionUtils.getFieldIfAvailable(beanProperty.beanClass(), beanProperty.targetField()))
.ifPresent(field -> this.propertyMappings.add(new PropertyMapping(beanProperty)));
}
}
private static final class PropertyMapping {
private final int sortCode;
private final DataFlow dataFlow;
private final Class> beanClass;
private final String fieldName;
private final String className;
PropertyMapping(final BeanProperty beanProperty) {
this.sortCode = beanProperty.sortCode();
this.dataFlow = beanProperty.dataFlow();
this.beanClass = beanProperty.beanClass();
this.fieldName = beanProperty.targetField();
this.className = beanProperty.converter().getName();
}
public int getSortCode() {
return sortCode;
}
public DataFlow getDataFlow() {
return dataFlow;
}
public Class> getBeanClass() {
return beanClass;
}
public String getFieldName() {
return fieldName;
}
boolean exists(final BeanProperty beanProperty) {
return this.dataFlow.equals(beanProperty.dataFlow())
&& this.beanClass.equals(beanProperty.beanClass())
&& this.fieldName.equals(beanProperty.targetField());
}
int compare(final PropertyMapping propertyMapping) {
if (this.sortCode != propertyMapping.getSortCode()) {
return Integer.compare(propertyMapping.getSortCode(), this.sortCode);
}
if (!this.beanClass.equals(propertyMapping.getBeanClass())) {
return propertyMapping.getBeanClass().getName().compareTo(this.beanClass.getName());
}
return propertyMapping.getFieldName().compareTo(this.fieldName);
}
@SuppressWarnings("unchecked")
Object convertData(final Object fieldValue, final Class> sourceClass) {
final Object wrapperObject;
if (fieldValue.getClass().isPrimitive()) {
Class> primitiveClass = fieldValue.getClass();
wrapperObject =
Optional.ofNullable(ReflectionUtils.findMethod(ClassUtils.primitiveWrapper(primitiveClass),
"valueOf", new Class[]{primitiveClass}))
.map(method -> ReflectionUtils.invokeMethod(method, null, new Object[]{fieldValue}))
.orElse(fieldValue);
} else {
wrapperObject = fieldValue;
}
return Optional.ofNullable(this.className)
.filter(StringUtils::notBlank)
.map(ClassUtils::forName)
.filter(converterClass ->
Adapter.class.isAssignableFrom(converterClass) && !Adapter.class.equals(converterClass))
.map(converterClass -> (Adapter