反射方法操作


透過反射操作共同方法

可以讓大家透過統一方式進行操作

  • EntityOperationUtils 共用方法
  • OperationObj 操作細項
  • JpaEnum JPA的操作步驟
  • PathConstant 靜態字串 放入實際物件的檔案結構
  1. 先準備細項
    OperationObj
    /
    @param repositoryName 操作資料庫的物件名稱
    @param method 操作資料庫的方法枚舉
    @param parameters 操作資料庫物件方法要處理的紀錄資訊
    @param entityName 紀錄名稱
    /

    @NoArgsConstructor
    @Data
    public class OperationObj {
    
     private String repositoryName;
    
     private Enum<?> method;
    
     private String params;
    
     private String entityName;
    
     private final Gson gson = new Gson();
    
     public OperationObj(String repositoryName, Enum<?> method, Object params, String entityName) {
         this.repositoryName = repositoryName;
         this.method = method;
         this.params = gson.toJson(params);
         this.entityName = entityName;
     }
    }
    

JpaEnum
必須要為repository內有的方法(與jpa有關聯)

public enum JpaEnum {
    saveAndFlush;
}

PathConstant

public class PathConstant {

    public static final String BASE_PACKAGE = "com.testModule.life";
    public static final String ENTITY_NAME = "com.testModule.life.entity."; // 尋找entity物件的完整路徑
    public static final String REPOSITORY_NAME = "com.testModule.life.repository.main."; // 尋找repository物件的完整路徑
}
  1. 核心方法
    EntityOperationUtils
    *多executeJpa來決定要操作資料庫物件處理資料表資料(調整一下命名其實也適用於各類自行建立的物件方法)

*doJpaSth明定JPA方法來處理資校 其實MethodUtils.invokeMethod已經實作了

@Component
public class EntityOperationUtils {

    @Autowired
    ApplicationContext applicationContext;

    private final Gson gson = new Gson();

    public Boolean executeJpa(List<OperationObj> opObjList) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        for (OperationObj opObj :opObjList) {
        String fullRepositoryPath=String.join("",PathConstant.REPOSITORY_MAIN_NAME,opObj.getRepositoryName());
        Class<?> repositoryClass = Class.forName(fullRepositoryPath);
        Object repository = applicationContext.getBean(repositoryClass);
        Method method = repository.getClass().getMethod(opObj.getMethod().toString(),Object.class);
        String fullEntityPath = String.join("",PathConstant.ENTITY_NAME + opObj.getEntityName());
        Class<?> entityClass = Class.forName(fullEntityPath); MethodUtils.invokeMethod(repository,true,method.getName(),gson.fromJson(opObj.getParams(), entityClass));
        }
        return true;
    }

public static Optional<?> doJpaSth(JpaRepository<?, ?> repository, String methodName, Object input, Class<?> argumentClassType) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Gson gson = new Gson();
        String inputStr = gson.toJson(input);
        Object inputObj = new Gson().fromJson(inputStr, argumentClassType);
        Method method = repository.getClass().getMethod(methodName, Object.class);
        Object obj = method.invoke(repository,inputObj);
        if (obj instanceof Optional) {
            return (Optional<?>) obj;
        }
        return Optional.of(obj);
    }

}

實際應用

 @Test
    void find() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        int pk = 1;
        Optional<Country> res = countryRepository.findById(pk);

        TypeReference<?> typeReference = new TypeReference<Country>() {
        };
        Class<?> classType = objectMapper.getTypeFactory().constructType(typeReference).getRawClass();

        // 可以根據需求放入 list/map/collection...的型別
        Optional<?> res2 = EntityOperationUtils.doJpaSth(countryRepository, "findById", pk, Integer.class);
        Object res2Opt = MethodUtils.invokeMethod(countryRepository, "findById", pk);
        if (res2Opt instanceof Optional<?>){
            res2=(Optional<?>) res2Opt;
        }
        log.info(new Gson().toJson(res2.get()));
        Country resO = (Country) res2.get();
        Assertions.assertEquals(res.get().getId(), resO.getId());
    }

片段程式碼

 Country updated = this.findByCountryId(id);
            if (Objects.isNull(updated)) {
                return Collections.emptyMap();
            }
 Country origin = (Country) SerialUtil.cloneObject(updated);
 updated.setDescription(description);
 OperationObj updateOp = new OperationObj("CountryRepository", JpaEnum.saveAndFlush, updated, "Country"); 
 // 異動實體表格
 List<OperationObj> updateOpList = Collections.singletonList(updateOp);
 entityOperationUtils.executeJpa(updateOpList);

看到這樣應用可能會覺得為什麼要多此一舉直接注入呼叫Jpa/自定義物件就好了
那我這邊列舉可能會用到的情境

  1. 當下沒有直接要對資料庫異動。例如:批次、審放、統一作法、觸發情境

這不是一個給新手的一個教學過程,也寫的不是很完整
希望大家多多包涵囉~

主要是給自己的一個紀錄,也分享給有需要的夥伴

這是一個心血來潮,產生的文章

若有喜歡或交流的部分都歡迎在下方留言,多多關照。

#reflaction #java







你可能感興趣的文章

【React Router】初次認識 React Router: v6 新語法 createBrowserRouter

【React Router】初次認識 React Router: v6 新語法 createBrowserRouter

 [10] 型別 - 內建型別、基本型別值

[10] 型別 - 內建型別、基本型別值

讓WebStorm識別alias

讓WebStorm識別alias






留言討論