All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nervousync.utils.BeanUtils Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
/*
 * 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) ObjectUtils.newInstance(converterClass)) .map(adapter -> convertData(adapter, sourceClass, wrapperObject)) .orElse(fieldValue); } Object convertData(final Adapter adapter, final Class beanClass, final Object wrapperObject) { try { switch (this.dataFlow) { case IN: if (adapter instanceof AbstractBeanAdapter) { ((AbstractBeanAdapter) adapter).setBeanClass(beanClass); } return adapter.unmarshal(wrapperObject); case OUT: return adapter.marshal(wrapperObject); default: return null; } } catch (Exception e) { LOGGER.error("Convert_Data_Error"); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Stack_Message_Error", e); } return null; } } boolean copyData(final int priority, final String fieldName, final Class sourceClass, final Object object, final Object... objects) { final Object targetObject; final String targetField; switch (this.dataFlow) { case IN: targetObject = object; targetField = fieldName; break; case OUT: targetObject = Arrays.stream(objects) .filter(obj -> obj != null && obj.getClass().equals(this.beanClass)) .findFirst() .orElse(null); targetField = this.fieldName; break; default: return Boolean.FALSE; } final Object fieldValue; switch (this.dataFlow) { case IN: fieldValue = Arrays.stream(objects) .filter(obj -> obj != null && obj.getClass().equals(this.beanClass)) .findFirst() .map(obj -> ReflectionUtils.getFieldValue(this.fieldName, obj)) .orElse(null); break; case OUT: fieldValue = ReflectionUtils.getFieldValue(fieldName, object); break; default: fieldValue = null; break; } if (targetObject != null && fieldValue != null && (DataFlow.OUT.equals(this.dataFlow) || (priority == Globals.DEFAULT_VALUE_INT || priority < this.sortCode))) { ReflectionUtils.setField(targetField, targetObject, this.convertData(fieldValue, sourceClass)); return Boolean.TRUE; } return Boolean.FALSE; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy