JavaBean Mutual Conversion
在升级公司架构过程中,发现有大量Entity与DTO相互转换的问题,并且其中还伴随DTO中的数据字典翻译,所以特意写个工具类,主要利用spring提供的BeanUtils工具类,用redis翻译字典
Among these features are:
-
Translate properties with @cacheformat in JavaBean
/** * Translate dictionary values that need to be translated in the current class * * @param source for translation */public static < t> void Dataformatter (T source) {//determines if the original object is null assert.notnull (source, "the original object to be translated cannot be null"); Get all properties and translate dictionary field[] Declaredfields = Source.getclass (). Getdeclaredfields (); Translation dictionaries: Find all attributes containing @cacheformatter stream<field> Fieldstream = Arrays.stream (declaredfields)/exclude no annotations @c Acheformatter field. filter (Field-field.isannotationpresent (Cacheformat.class)); Translation Doformatter (Fieldstream, Source, Source.getclass ()); }
-
Translate list
/** * Translate dictionary values that need to be translated in the current collection class * * @param sources The collection object to be translated * * public static <T> void Datafo Rmatter (list<t> sources) {//when the set of translations is empty, returns an empty collection if (sources = = NULL | | sources.isempty ()) {return; } Class targetclass = Sources.get (0). GetClass (); Get all properties and translate dictionary field[] Declaredfields = Targetclass.getdeclaredfields (); Translation dictionaries: Find all attributes containing @cacheformat list<field> formatterfields = Arrays.stream (declaredfields)/exclude no annotations Cacheformat field. filter (Field-field.isannotationpresent (Cacheformat.class)). Collect (Collectors . ToList ()); Loop list (parallel operation) Sources.parallelstream (). ForEach (target, {//Translation Doformatter (Formatterfields.stream () , Target, Targetclass); });}
-
Entity vs. dto
/** * Converts the original object to the object of the target class and translates the property dictionary for the target class * Only for the target class with no pattern or paradigm as the original object * @param source original Object * @para M Targetclass Target class * @return target object */public static <T> T Dataconvert (object source, class<t> Targetclass) {A Ssert.istrue (Source = null && Targetclass! = null, "the original object or target class cannot be null"); T target = Beanutils.instantiateclass (Targetclass); Sets the property of the target object to the corresponding attribute in the original object Beanutils.copyproperties (source, target); Dataformatter (target); return target;} /** * Entity Properties Cross-transfer * * @param source Original object * @param target target object * @return Destination object */public static <T> T Dataobjconvert (Object s Ource, T target) {assert.istrue (source! = NULL && target! = NULL, "the original object or target object to be converted cannot be null"); Convert beanutils.copyproperties (source, target); Translation Dataformatter (target); return target;}
-
List
/** * Bulk Convert the original object to the target object and translate the target object's property dictionary * if you want to return a collection of the specified type that is a subclass of List, refer to {@link hybeanutils# DATACONVERTS2} * * @param sources The original object collection * @param targetclass the target object's class * @return return the converted target collection */public static <t, e> List<t> Dataconverts (list<e> sources, class<t> targetclass) {assert.notnull (TargetClass, " The target class for the conversion cannot be null "); When the set of translations is empty, returns an empty collection if (sources = = NULL | | sources.isempty ()) {list<t> TargetList = new Arraylist<> ( ); return targetlist; }//Gets the type of the original collection class<? Extends list> AClass = Sources.getclass (); Target set list<t> TargetList = Beanutils.instantiateclass (AClass); Sets the property of the target object to the corresponding attribute in the original object (parallel operation) Sources.parallelstream (). ForEach (item, {T target = Beanutils.instantiateclass (Targetclass); Beanutils.copyproperties (item, target); Targetlist.add (target); }); Translation dictionary dataformatter (targetlist); return targetlist; }
This is the upgraded version of the list conversion T
/** * 返回指定类型的方法,这里的类型必须是List的子类 * 批量把原对象转换成目标对象,并翻译目标对象的属性字典, * * @param sources 原对象集合 * @param targetClass 目标对象的类 * @param returnType 返回值类型 * @return 返回转换后的目标集合 */public static <T, E, R extends List<T>> R dataConverts2(List<E> sources, Class<T> targetClass, Class<R> returnType) { Assert.notNull(targetClass, "转换的目标Class不能为null"); Assert.notNull(returnType, "返回值类型Class不能为null"); //当翻译的集合为空时,返回空的集合 if (sources == null || sources.isEmpty()) { return null; } //目标集合 R targetList = BeanUtils.instantiateClass(returnType); //把目标对象的属性设置成原对象中对应的属性(并行操作) sources.parallelStream().forEach(item -> { T target = BeanUtils.instantiateClass(targetClass); BeanUtils.copyProperties(item, target); targetList.add(target); }); //翻译字典 dataFormatter(targetList); return targetList;}
The public methods used above
/** * Translate fields that need to be translated by the target class * * @param stream * @param target target object * @param Targetclass object class */private static <T> vo ID Doformatter (stream<field> Stream, Object target, class<t> targetclass) {//exclude field Stream with null field value in target object. Filter (field, {PropertyDescriptor PropertyDescriptor = Beanutils.getpropertydescriptor (Targetclass, Field.get Name ()); Object invoke = null; try {invoke = Propertydescriptor.getreadmethod (). Invoke (target, new object[]{}); } catch (Illegalaccessexception e) {Logger.warn ("Get for field to be translated is unreachable", e); } catch (InvocationTargetException e) {Logger.warn ("Call the Get method times error for the field to be translated", E); } catch (Exception e) {Logger.warn ("ensure property has Get,set method", e); } return Invoke! = NULL; Traversal of the field to be translated}). ForEach (Field-cacheformat annotation = field.getannotation (Cacheformat.class); The cache system number, if not specified, defaults to the current system number String Systemcode = "System_code"; if (Stringutils.isnotblank (Annotation.systemcode ())) {Systemcode = Annotation.systemcode (); }//Cache key, if not specified, the default is the field name String key = Annotation.key (); if (Stringutils.isblank (key)) {key = Field.getname (); }//Determine if the annotation @cacheformatter specifies to translate the dictionary to another field on String Formatterfield = Annotation.destination (); if (Stringutils.isblank (Formatterfield)) {//When no other field is specified in the annotation, the default translates to annotated properties Formatterfield = Field.getnam E (); try {propertydescriptor orginpropertydescriptor = Beanutils.getpropertydescriptor (targetclass, field. GetName ()); Object value = Orginpropertydescriptor.getreadmethod (). Invoke (target, new object[]{}); Set the Target Field value propertydescriptor PropertyDescriptor = Beanutils.getpropertydescriptor (Targetclass, FormatterField); Fetch cache String Cachevalue = redisutils.hget (Systemcode + ": Valueset:" + key, Value + ""); Such asIf the query is not in the data dictionary, take the IF in the business cache (Stringutils.isblank (cachevalue)) {Cachevalue = Redisutils.hget (Systemco De + ": valueset:" + key, Value + ""); } assert.haslength (Cachevalue, "+ Value +" corresponding cache not found in cache + key +); Set the cache value to the attribute field in Propertydescriptor.getwritemethod (). Invoke (target, cachevalue); } catch (Illegalaccessexception e) {Logger.warn ("the set of fields to be translated is inaccessible", e); } catch (InvocationTargetException e) {Logger.warn ("call the Set method of the field to be translated times wrong", e); } catch (Exception e) {e.printstacktrace (); Logger.warn ("Call the Set method of the field to be translated times wrong, guess type mismatch", e); } });}
Note Cacheformat
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface CacheFormat { /** * 缓存key * @return */ String key(); /** * 指定翻译值存放字段, 例如:userType的翻译结果放到userTypeName上 * @return */ String destination() default ""; /** * 系统编号 * @return */ String systemCode() default "";
Note: This translation focuses only on the first layer, the properties of the current object, and does not recursively translate
For example, the current class has an attribute as an object instance, and the object has a property that is @cacheformat annotated
The tool class does not translate the attributes in this property and requires the developer to first convert the property with the current tool class
And then set it to the target class.
Beanutils--javabean Mutual conversion and dictionary translation