001/** 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.table; 017 018import com.mybatisflex.annotation.InsertListener; 019import com.mybatisflex.annotation.KeyType; 020import com.mybatisflex.annotation.SetListener; 021import com.mybatisflex.annotation.UpdateListener; 022import com.mybatisflex.core.FlexConsts; 023import com.mybatisflex.core.FlexGlobalConfig; 024import com.mybatisflex.core.exception.FlexExceptions; 025import com.mybatisflex.core.javassist.ModifyAttrsRecord; 026import com.mybatisflex.core.mybatis.TypeHandlerObject; 027import com.mybatisflex.core.query.*; 028import com.mybatisflex.core.row.Row; 029import com.mybatisflex.core.tenant.TenantManager; 030import com.mybatisflex.core.util.*; 031import org.apache.ibatis.mapping.ResultFlag; 032import org.apache.ibatis.mapping.ResultMap; 033import org.apache.ibatis.mapping.ResultMapping; 034import org.apache.ibatis.reflection.MetaObject; 035import org.apache.ibatis.reflection.Reflector; 036import org.apache.ibatis.reflection.ReflectorFactory; 037import org.apache.ibatis.session.Configuration; 038import org.apache.ibatis.type.TypeHandler; 039 040import java.util.*; 041 042public class TableInfo { 043 044 private String schema; //schema 045 private String tableName; //表名 046 private Class<?> entityClass; //实体类 047 private boolean camelToUnderline = true; 048 private String dataSource; 049 050 //逻辑删除数据库列名 051 private String logicDeleteColumn; 052 053 //乐观锁字段 054 private String versionColumn; 055 056 //租户ID 字段 057 private String tenantIdColumn; 058 059 //数据插入时,默认插入数据字段 060 private Map<String, String> onInsertColumns; 061 062 //数据更新时,默认更新内容的字段 063 private Map<String, String> onUpdateColumns; 064 065 //大字段列 066 private String[] largeColumns = new String[0]; 067 068 // 所有的字段,但除了主键的列 069 private String[] columns = new String[0]; 070 071 //主键字段 072 private String[] primaryKeys = new String[0]; 073 074 //在插入数据的时候,支持主动插入的主键字段 075 //通过自定义生成器生成 或者 Sequence 在 before 生成的时候,是需要主动插入数据的 076 private String[] insertPrimaryKeys; 077 078 private List<ColumnInfo> columnInfoList; 079 private List<IdInfo> primaryKeyList; 080 081 //column 和 java 属性的称的关系映射 082 private Map<String, ColumnInfo> columnInfoMapping = new HashMap<>(); 083 private Map<String, String> propertyColumnMapping = new HashMap<>(); 084 085 private InsertListener onInsertListener; 086 private UpdateListener onUpdateListener; 087 private SetListener onSetListener; 088 089 090 private final ReflectorFactory reflectorFactory = new BaseReflectorFactory() { 091 @Override 092 public Reflector findForClass(Class<?> type) { 093 return getReflector(); 094 } 095 }; 096 private Reflector reflector; //反射工具 097 098 public String getSchema() { 099 return schema; 100 } 101 102 public void setSchema(String schema) { 103 this.schema = schema; 104 } 105 106 public String getTableName() { 107 return tableName; 108 } 109 110 public void setTableName(String tableName) { 111 this.tableName = tableName; 112 } 113 114 public Class<?> getEntityClass() { 115 return entityClass; 116 } 117 118 public void setEntityClass(Class<?> entityClass) { 119 this.entityClass = entityClass; 120 } 121 122 public boolean isCamelToUnderline() { 123 return camelToUnderline; 124 } 125 126 public void setCamelToUnderline(boolean camelToUnderline) { 127 this.camelToUnderline = camelToUnderline; 128 } 129 130 public String getDataSource() { 131 return dataSource; 132 } 133 134 public void setDataSource(String dataSource) { 135 this.dataSource = dataSource; 136 } 137 138 public String getLogicDeleteColumn() { 139 return logicDeleteColumn; 140 } 141 142 public void setLogicDeleteColumn(String logicDeleteColumn) { 143 this.logicDeleteColumn = logicDeleteColumn; 144 } 145 146 public String getVersionColumn() { 147 return versionColumn; 148 } 149 150 public void setVersionColumn(String versionColumn) { 151 this.versionColumn = versionColumn; 152 } 153 154 public String getTenantIdColumn() { 155 return tenantIdColumn; 156 } 157 158 public void setTenantIdColumn(String tenantIdColumn) { 159 this.tenantIdColumn = tenantIdColumn; 160 } 161 162 public Map<String, String> getOnInsertColumns() { 163 return onInsertColumns; 164 } 165 166 public void setOnInsertColumns(Map<String, String> onInsertColumns) { 167 this.onInsertColumns = onInsertColumns; 168 } 169 170 public Map<String, String> getOnUpdateColumns() { 171 return onUpdateColumns; 172 } 173 174 public void setOnUpdateColumns(Map<String, String> onUpdateColumns) { 175 this.onUpdateColumns = onUpdateColumns; 176 } 177 178 public String[] getLargeColumns() { 179 return largeColumns; 180 } 181 182 public void setLargeColumns(String[] largeColumns) { 183 this.largeColumns = largeColumns; 184 } 185 186 public String[] getInsertPrimaryKeys() { 187 return insertPrimaryKeys; 188 } 189 190 public void setInsertPrimaryKeys(String[] insertPrimaryKeys) { 191 this.insertPrimaryKeys = insertPrimaryKeys; 192 } 193 194 public Reflector getReflector() { 195 return reflector; 196 } 197 198 public ReflectorFactory getReflectorFactory() { 199 return reflectorFactory; 200 } 201 202 public void setReflector(Reflector reflector) { 203 this.reflector = reflector; 204 } 205 206 public String[] getColumns() { 207 return columns; 208 } 209 210 211 public void setColumns(String[] columns) { 212 this.columns = columns; 213 } 214 215 public String[] getPrimaryKeys() { 216 return primaryKeys; 217 } 218 219 public void setPrimaryKeys(String[] primaryKeys) { 220 this.primaryKeys = primaryKeys; 221 } 222 223 224 public InsertListener getOnInsertListener() { 225 return onInsertListener; 226 } 227 228 public void setOnInsertListener(InsertListener onInsertListener) { 229 this.onInsertListener = onInsertListener; 230 } 231 232 public UpdateListener getOnUpdateListener() { 233 return onUpdateListener; 234 } 235 236 public void setOnUpdateListener(UpdateListener onUpdateListener) { 237 this.onUpdateListener = onUpdateListener; 238 } 239 240 public SetListener getOnSetListener() { 241 return onSetListener; 242 } 243 244 public void setOnSetListener(SetListener onSetListener) { 245 this.onSetListener = onSetListener; 246 } 247 248 public List<ColumnInfo> getColumnInfoList() { 249 return columnInfoList; 250 } 251 252 253 void setColumnInfoList(List<ColumnInfo> columnInfoList) { 254 this.columnInfoList = columnInfoList; 255 this.columns = new String[columnInfoList.size()]; 256 for (int i = 0; i < columnInfoList.size(); i++) { 257 ColumnInfo columnInfo = columnInfoList.get(i); 258 columns[i] = columnInfo.getColumn(); 259 columnInfoMapping.put(columnInfo.column, columnInfo); 260 propertyColumnMapping.put(columnInfo.property, columnInfo.column); 261 } 262 } 263 264 265 public List<IdInfo> getPrimaryKeyList() { 266 return primaryKeyList; 267 } 268 269 void setPrimaryKeyList(List<IdInfo> primaryKeyList) { 270 this.primaryKeyList = primaryKeyList; 271 this.primaryKeys = new String[primaryKeyList.size()]; 272 273 List<String> insertIdFields = new ArrayList<>(); 274 for (int i = 0; i < primaryKeyList.size(); i++) { 275 IdInfo idInfo = primaryKeyList.get(i); 276 primaryKeys[i] = idInfo.getColumn(); 277 278 if (idInfo.getKeyType() != KeyType.Auto && (idInfo.getBefore() != null && idInfo.getBefore())) { 279 insertIdFields.add(idInfo.getColumn()); 280 } 281 282 columnInfoMapping.put(idInfo.column, idInfo); 283 propertyColumnMapping.put(idInfo.property, idInfo.column); 284 } 285 this.insertPrimaryKeys = insertIdFields.toArray(new String[0]); 286 } 287 288 289 /** 290 * 插入(新增)数据时,获取所有要插入的字段 291 * 292 * @return 字段列表 293 */ 294 public String[] obtainInsertColumns() { 295 return ArrayUtil.concat(insertPrimaryKeys, columns); 296 } 297 298 299 /** 300 * 构建 insert 的 Sql 参数 301 * 302 * @param entity 从 entity 中获取 303 * @return 数组 304 */ 305 public Object[] buildInsertSqlArgs(Object entity) { 306 MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory); 307 String[] insertColumns = obtainInsertColumns(); 308 309 List<Object> values = new ArrayList<>(insertColumns.length); 310 for (String insertColumn : insertColumns) { 311 if (onInsertColumns == null || !onInsertColumns.containsKey(insertColumn)) { 312 Object value = buildColumnSqlArg(metaObject, insertColumn); 313 values.add(value); 314 } 315 } 316 return values.toArray(); 317 } 318 319 320 /** 321 * 获取要修改的值 322 * 323 * @param entity 324 * @param ignoreNulls 325 */ 326 public Set<String> obtainUpdateColumns(Object entity, boolean ignoreNulls, boolean includePrimary) { 327 MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory); 328 Set<String> columns = new LinkedHashSet<>(); //需使用 LinkedHashSet 保证 columns 的顺序 329 if (entity instanceof ModifyAttrsRecord) { 330 Set<String> properties = ((ModifyAttrsRecord) entity).obtainModifyAttrs(); 331 if (properties.isEmpty()) { 332 return Collections.emptySet(); 333 } 334 for (String property : properties) { 335 String column = propertyColumnMapping.get(property); 336 if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) { 337 continue; 338 } 339 340 //过滤乐观锁字段 和 租户字段 341 if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) { 342 continue; 343 } 344 345 if (!includePrimary && ArrayUtil.contains(primaryKeys, column)) { 346 continue; 347 } 348 349 // ModifyAttrsRecord 忽略 ignoreNulls 的设置 350 // Object value = getPropertyValue(metaObject, property); 351 // if (ignoreNulls && value == null) { 352 // continue; 353 // } 354 columns.add(column); 355 } 356 } 357 //not ModifyAttrsRecord 358 else { 359 for (String column : this.columns) { 360 if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) { 361 continue; 362 } 363 364 //过滤乐观锁字段 和 租户字段 365 if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) { 366 continue; 367 } 368 369 Object value = buildColumnSqlArg(metaObject, column); 370 if (ignoreNulls && value == null) { 371 continue; 372 } 373 374 columns.add(column); 375 } 376 377 // 普通 entity(非 ModifyAttrsRecord) 忽略 includePrimary 的设置 378// if (includePrimary) { 379// for (String column : this.primaryKeys) { 380// Object value = getColumnValue(metaObject, column); 381// if (ignoreNulls && value == null) { 382// continue; 383// } 384// columns.add(column); 385// } 386// } 387 } 388 return columns; 389 } 390 391 /** 392 * 获取所有要修改的值,默认为全部除了主键以外的字段 393 * 394 * @param entity 实体对象 395 * @return 数组 396 */ 397 public Object[] buildUpdateSqlArgs(Object entity, boolean ignoreNulls, boolean includePrimary) { 398 MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory); 399 List<Object> values = new ArrayList<>(); 400 if (entity instanceof ModifyAttrsRecord) { 401 Set<String> properties = ((ModifyAttrsRecord) entity).obtainModifyAttrs(); 402 if (properties.isEmpty()) { 403 return values.toArray(); 404 } 405 for (String property : properties) { 406 String column = propertyColumnMapping.get(property); 407 if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) { 408 continue; 409 } 410 //过滤乐观锁字段 和 租户字段 411 if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) { 412 continue; 413 } 414 415 if (!includePrimary && ArrayUtil.contains(primaryKeys, column)) { 416 continue; 417 } 418 419 Object value = getPropertyValue(metaObject, property); 420 421 // ModifyAttrsRecord 忽略 ignoreNulls 的设置, 422 // 当使用 ModifyAttrsRecord 时,可以理解为要对字段进行 null 值进行更新,否则没必要使用 ModifyAttrsRecord 423 // if (ignoreNulls && value == null) { 424 // continue; 425 // } 426 values.add(value); 427 } 428 } 429 // normal entity. not ModifyAttrsRecord 430 else { 431 for (String column : this.columns) { 432 if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) { 433 continue; 434 } 435 436 //过滤乐观锁字段 和 租户字段 437 if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) { 438 continue; 439 } 440 441 // 普通 entity 忽略 includePrimary 的设置, 442 // 因为 for 循环中的 this.columns 本身就不包含有主键 443 // if (includePrimary) { 444 // } 445 446 Object value = buildColumnSqlArg(metaObject, column); 447 if (ignoreNulls && value == null) { 448 continue; 449 } 450 451 values.add(value); 452 } 453 } 454 455 return values.toArray(); 456 } 457 458 459 /** 460 * 构建主键的 sql 参数数据 461 * 462 * @param entity 463 */ 464 public Object[] buildPkSqlArgs(Object entity) { 465 MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory); 466 Object[] values = new Object[primaryKeys.length]; 467 for (int i = 0; i < primaryKeys.length; i++) { 468 values[i] = buildColumnSqlArg(metaObject, primaryKeys[i]); 469 } 470 return values; 471 } 472 473 474 public Object[] buildTenantIdArgs() { 475 if (StringUtil.isBlank(tenantIdColumn)) { 476 return null; 477 } 478 479 return TenantManager.getTenantIds(); 480 } 481 482 private static final String APPEND_CONDITIONS_FLAG = "appendConditions"; 483 484 public void appendConditions(Object entity, QueryWrapper queryWrapper) { 485 486 Object appendConditions = CPI.getContext(queryWrapper, APPEND_CONDITIONS_FLAG); 487 if (Boolean.TRUE.equals(appendConditions)) { 488 return; 489 } else { 490 CPI.putContext(queryWrapper, APPEND_CONDITIONS_FLAG, Boolean.TRUE); 491 } 492 493 //添加乐观锁条件,只有在 update 的时候进行处理 494 if (StringUtil.isNotBlank(versionColumn) && entity != null) { 495 Object versionValue = buildColumnSqlArg(entity, versionColumn); 496 if (versionValue == null) { 497 throw FlexExceptions.wrap("The version value of entity[%s] must not be null.", entity); 498 } 499 queryWrapper.and(QueryCondition.create(tableName, versionColumn, QueryCondition.LOGIC_EQUALS, versionValue)); 500 } 501 502 //逻辑删除条件,已删除的数据不能被修改 503 if (StringUtil.isNotBlank(logicDeleteColumn)) { 504 queryWrapper.and(QueryCondition.create(tableName, logicDeleteColumn, QueryCondition.LOGIC_EQUALS 505 , FlexGlobalConfig.getDefaultConfig().getNormalValueOfLogicDelete())); 506 } 507 508 //多租户 509 Object[] tenantIdArgs = buildTenantIdArgs(); 510 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 511 if (tenantIdArgs.length == 1) { 512 queryWrapper.and(QueryCondition.create(tableName, tenantIdColumn, QueryCondition.LOGIC_EQUALS, tenantIdArgs[0])); 513 } else { 514 queryWrapper.and(QueryCondition.create(tableName, tenantIdColumn, QueryCondition.LOGIC_IN, tenantIdArgs)); 515 } 516 } 517 518 //子查询 519 List<QueryWrapper> childSelects = CPI.getChildSelect(queryWrapper); 520 if (CollectionUtil.isNotEmpty(childSelects)) { 521 for (QueryWrapper childQueryWrapper : childSelects) { 522 List<QueryTable> queryTables = CPI.getQueryTables(childQueryWrapper); 523 for (QueryTable queryTable : queryTables) { 524 TableInfo tableInfo = TableInfoFactory.ofTableName(queryTable.getName()); 525 if (tableInfo != null) { 526 tableInfo.appendConditions(entity, childQueryWrapper); 527 } 528 } 529 } 530 } 531 532 //union 533 List<UnionWrapper> unions = CPI.getUnions(queryWrapper); 534 if (CollectionUtil.isNotEmpty(unions)) { 535 for (UnionWrapper union : unions) { 536 QueryWrapper unionQueryWrapper = union.getQueryWrapper(); 537 List<QueryTable> queryTables = CPI.getQueryTables(unionQueryWrapper); 538 for (QueryTable queryTable : queryTables) { 539 TableInfo tableInfo = TableInfoFactory.ofTableName(queryTable.getName()); 540 if (tableInfo != null) { 541 tableInfo.appendConditions(entity, unionQueryWrapper); 542 } 543 } 544 } 545 } 546 547 } 548 549 550 public String getKeyProperties() { 551 StringJoiner joiner = new StringJoiner(","); 552 for (IdInfo value : primaryKeyList) { 553 joiner.add(FlexConsts.ENTITY + "." + value.getProperty()); 554 } 555 return joiner.toString(); 556 } 557 558 559 public String getKeyColumns() { 560 StringJoiner joiner = new StringJoiner(","); 561 for (IdInfo value : primaryKeyList) { 562 joiner.add(value.getColumn()); 563 } 564 return joiner.toString(); 565 } 566 567 public ResultMap buildResultMap(Configuration configuration) { 568 String resultMapId = entityClass.getName(); 569 List<ResultMapping> resultMappings = new ArrayList<>(); 570 571 for (ColumnInfo columnInfo : columnInfoList) { 572 ResultMapping mapping = new ResultMapping.Builder(configuration, columnInfo.getProperty(), 573 columnInfo.getColumn(), columnInfo.getPropertyType()) 574 .jdbcType(columnInfo.getJdbcType()) 575 .typeHandler(columnInfo.buildTypeHandler()) 576 .build(); 577 resultMappings.add(mapping); 578 } 579 580 for (IdInfo idInfo : primaryKeyList) { 581 ResultMapping mapping = new ResultMapping.Builder(configuration, idInfo.getProperty(), 582 idInfo.getColumn(), idInfo.getPropertyType()) 583 .flags(CollectionUtil.newArrayList(ResultFlag.ID)) 584 .jdbcType(idInfo.getJdbcType()) 585 .typeHandler(idInfo.buildTypeHandler()) 586 .build(); 587 resultMappings.add(mapping); 588 } 589 590 return new ResultMap.Builder(configuration, resultMapId, entityClass, resultMappings).build(); 591 } 592 593 594 private Object buildColumnSqlArg(MetaObject metaObject, String column) { 595 ColumnInfo columnInfo = columnInfoMapping.get(column); 596 Object value = getPropertyValue(metaObject, columnInfo.property); 597 598 TypeHandler typeHandler = columnInfo.buildTypeHandler(); 599 if (value != null && typeHandler != null) { 600 return new TypeHandlerObject(typeHandler, value, columnInfo.getJdbcType()); 601 } 602 603 return value; 604 } 605 606 607 public Object buildColumnSqlArg(Object entityObject, String column) { 608 MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory); 609 return buildColumnSqlArg(metaObject, column); 610 } 611 612 613 private Object getPropertyValue(MetaObject metaObject, String property) { 614 if (property != null && metaObject.hasGetter(property)) { 615 return metaObject.getValue(property); 616 } 617 return null; 618 } 619 620 621 /** 622 * 通过 row 实例类转换为一个 entity 623 * 624 * @return entity 625 */ 626 public <T> T newInstanceByRow(Row row) { 627 Object instance = ClassUtil.newInstance(entityClass); 628 MetaObject metaObject = EntityMetaObject.forObject(instance, reflectorFactory); 629 for (String column : row.keySet()) { 630 ColumnInfo columnInfo = columnInfoMapping.get(column); 631 if (columnInfo != null && metaObject.hasSetter(columnInfo.property)) { 632 Object value = ConvertUtil.convert(row.get(column), metaObject.getSetterType(columnInfo.property)); 633 if (onSetListener != null) { 634 value = onSetListener.onSet(instance, columnInfo.property, value); 635 } 636 metaObject.setValue(columnInfo.property, value); 637 } 638 } 639 return (T) instance; 640 } 641 642 643 /** 644 * 初始化乐观锁版本号 645 * 646 * @param entityObject 647 */ 648 public void initVersionValueIfNecessary(Object entityObject) { 649 if (StringUtil.isBlank(versionColumn)) { 650 return; 651 } 652 653 MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory); 654 Object columnValue = getPropertyValue(metaObject, columnInfoMapping.get(versionColumn).property); 655 if (columnValue == null) { 656 String name = columnInfoMapping.get(versionColumn).property; 657 Class<?> clazz = metaObject.getSetterType(name); 658 metaObject.setValue(name, ConvertUtil.convert(0L, clazz)); 659 } 660 } 661 662 /** 663 * 设置租户id 664 * 665 * @param entityObject 666 */ 667 public void initTenantIdIfNecessary(Object entityObject) { 668 if (StringUtil.isBlank(tenantIdColumn)) { 669 return; 670 } 671 672 MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory); 673 Object[] tenantIds = TenantManager.getTenantIds(); 674 if (tenantIds == null || tenantIds.length == 0) { 675 return; 676 } 677 678 //默认使用第一个作为插入的租户ID 679 Object tenantId = tenantIds[0]; 680 if (tenantId != null) { 681 metaObject.setValue(columnInfoMapping.get(tenantIdColumn).property, tenantId); 682 } 683 } 684 685 /** 686 * 初始化逻辑删除的默认值 687 * 688 * @param entityObject 689 */ 690 public void initLogicDeleteValueIfNecessary(Object entityObject) { 691 if (StringUtil.isBlank(logicDeleteColumn)) { 692 return; 693 } 694 695 MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory); 696 Object columnValue = getPropertyValue(metaObject, columnInfoMapping.get(logicDeleteColumn).property); 697 if (columnValue == null) { 698 String name = columnInfoMapping.get(logicDeleteColumn).property; 699 Class<?> clazz = metaObject.getSetterType(name); 700 if (Number.class.isAssignableFrom(clazz)){ 701 metaObject.setValue(name, ConvertUtil.convert(0L, clazz)); 702 }else if (clazz == Boolean.class){ 703 metaObject.setValue(name, false); 704 } 705 } 706 } 707 708 709 public void invokeOnInsertListener(Object entity) { 710 if (onInsertListener != null) { 711 onInsertListener.onInsert(entity); 712 return; 713 } 714 715 InsertListener globalInsertListener = FlexGlobalConfig.getDefaultConfig().getInsertListener(entityClass); 716 if (globalInsertListener != null) { 717 globalInsertListener.onInsert(entity); 718 } 719 } 720 721 722 public void invokeOnUpdateListener(Object entity) { 723 if (onUpdateListener != null) { 724 onUpdateListener.onUpdate(entity); 725 return; 726 } 727 728 UpdateListener globalUpdateListener = FlexGlobalConfig.getDefaultConfig().getUpdateListener(entityClass); 729 if (globalUpdateListener != null) { 730 globalUpdateListener.onUpdate(entity); 731 } 732 } 733 734 735 public Object invokeOnSetListener(Object entity, String property, Object value) { 736 if (onSetListener != null) { 737 return onSetListener.onSet(entity, property, value); 738 } 739 740 SetListener globalSetListener = FlexGlobalConfig.getDefaultConfig().getSetListener(entityClass); 741 if (globalSetListener != null) { 742 return globalSetListener.onSet(entity, property, value); 743 } 744 745 return value; 746 } 747}