ic_excellent 2023-03-15 16:14:48 +08:00
commit 7710f96dfe
870 changed files with 141578 additions and 2073 deletions

1
.gitignore vendored
View File

@ -46,4 +46,5 @@ src/test/resources/font
src/main/resources/WEB-INF/vm/outFile
target/
*.back
src/main/old_src/

View File

@ -47,6 +47,8 @@ jQuery().ready(function(){
}
}
addRowBack(2, configObj);
changeDetailFieldReadOnly(detailTable, detail2ComPayDateId, detail2PaymentTypeId, computeDatePayType)
// 主表字段发生变化

View File

@ -42,6 +42,8 @@ function getDate(time) {
return y + "-" + (m < 10 ? "0" + m : m) + "-" + (d < 10 ? "0" + d : d);
}
/**
* 校验比例是否等于100
* @param detailTable 明细表
@ -153,6 +155,18 @@ function changeDetailPayDate(obj){
}
}
/**
* 字段联动后添加明细行后执行的逻辑
* @param detail
* @param configObj
*/
function addRowBack(detail, configObj){
WfForm.registerAction(WfForm.ACTION_ADDROW + detail, function(index){
configObj.index = index;
changeDetailPayDate(configObj);
});
}
/**
* 改变明细表字段只读
* @param detailTable
@ -173,3 +187,5 @@ function changeDetailFieldReadOnly(detailTable, detailComDateField, detailPaymen
}
}
}

View File

@ -0,0 +1,31 @@
// 存货分类编码
const chflbmId = WfForm.convertFieldNameToId("chflbm");
// 流程类型
const workflowType = WfForm.convertFieldNameToId("lcxz");
// 唯一编码
const unqieCode = WfForm.convertFieldNameToId("wybm");
// 帐套查询
const zt = WfForm.convertFieldNameToId("ztcx");
// 存货编码
const chbm = WfForm.convertFieldNameToId("chbm2");
changeVal();
WfForm.bindFieldChangeEvent(chflbmId, function(obj,id,value){
changeVal();
});
function changeVal(){
let value = WfForm.getFieldValue(chflbmId)
console.log('value: ', value);
if(!value){
return;
}
let firstVal = value.charAt(0);
if(firstVal == 0){
value = value.substring(1, value.length);
console.log('修改后的val ', value);
setTimeout(()=>{
$(`#${chflbmId}span`)[0].innerHTML = value;
},5);
}
}

View File

@ -0,0 +1,32 @@
// 主表预计付款日期
const yjfksj = WfForm.convertFieldNameToId('yjfksj');
// 主表比例
const bl = WfForm.convertFieldNameToId('bcfkbl');
// 明细要求付款日期
const detail3Yqfkrq = WfForm.convertFieldNameToId('yqfkrq',"detail_3");
// 明细本次付款比例
const detailBl = WfForm.convertFieldNameToId('bcfkbl',"detail_3");
WfForm.registerCheckEvent(WfForm.OPER_ADDROW + "3", function (callback) {
callback();
initDeatail3Date();
});
WfForm.bindFieldChangeEvent(`${yjfksj},${bl}`, function(obj,id,value){
initDeatail3Date();
});
function initDeatail3Date(){
let dateVal = WfForm.getFieldValue(yjfksj);
let blVal = WfForm.getFieldValue(bl);
console.log('dateVal ', dateVal);
console.log('blVal ', blVal);
let detail3RowArr = WfForm.getDetailAllRowIndexStr('detail_3').split(",");
for (let i = 0; i < detail3RowArr.length; i++) {
let rowIndex = detail3RowArr[i];
if (rowIndex !== "") {
WfForm.changeFieldValue(`${detail3Yqfkrq}_${rowIndex}`,{value: dateVal});
WfForm.changeFieldValue(`${detailBl}_${rowIndex}`,{value: blVal});
}
}
}

View File

@ -0,0 +1,217 @@
var m_xmmc = WfForm.convertFieldNameToId("xmmc");//项目名称
var m_bmwyz = WfForm.convertFieldNameToId("glkcjlb");//关联勘察
var m_bmwyz1 = WfForm.convertFieldNameToId("glxsxqd");//关联销售
var m_bmwyz2 = WfForm.convertFieldNameToId("chdadx");//唯一值多选
var dt2_tyrq = WfForm.convertFieldNameToId("tyrq", "detail_2");//明细2停用日期
jQuery(document).ready(function () {
setTimeout("bindFieldChange()", "500");
});
function bindFieldChange() {
WfForm.bindFieldChangeEvent(m_xmmc, function (obj, id, value) {
WfForm.changeFieldValue(m_bmwyz, {value: ''});
WfForm.changeFieldValue(m_bmwyz1, {value: ''});
WfForm.changeFieldValue(m_bmwyz2, {value: ''});
});
//提交检验
WfForm.registerCheckEvent(WfForm.OPER_SUBMIT, function (callback) {
var flag = true;
var rowArr = WfForm.getDetailAllRowIndexStr("detail_2").split(",");
for (var i = 0; i < rowArr.length; i++) {
var rowid = rowArr[i];
var dt2_tyrq_v = WfForm.getFieldValue(dt2_tyrq + "_" + rowid);
if (dt2_tyrq_v != "") {
WfForm.showMessage("明细2第" + (i + 1) + "行设备已在" + dt2_tyrq_v + "停用!", 2, 5);
flag = flase;
break;
}
}
if (flag) {
callback(); //继续提交需调用callback不调用代表阻断
}
});
}
var rowArr = WfForm.getDetailAllRowIndexStr("detail_3").split(",");
// WfForm.delDetailRow("detail_2", "all");
for (var i = 0; i < rowArr.length; i++) {
var rowIndex = rowArr[i];
if (rowIndex !== "") {
var fieldMark = "field12566" + rowIndex;
if (fieldMark === "0") {
var count = WfForm.getFieldValue("field12562" + rowIndex);
var field7108_ = WfForm.getFieldValue("field6117_" + rowIndex);
WfForm.addDetailRow("detail_2", {field8567: {value: count}, field7583: {value: field7108_},});
}
}
}
/*
dev-1 王宣然 限制明细表选择的bom不能重复
*/
const detailBomField = WfForm.convertFieldNameToId('bombm', 'detail_1');
/**
* 主表辅助字段
*/
const mainAttrField = WfForm.convertFieldNameToId('ycbmpzx');
/**
* 明细1数量
*/
const detail1NumFieldId = WfForm.convertFieldNameToId('sl1', "detail_1");
/**
* 明细3 明细2数量
*/
const detail3NumFieldId = WfForm.convertFieldNameToId('mx2sl', "detail_3");
/**
* 明细3数量
*/
const detail3NumFieldId2 = WfForm.convertFieldNameToId('sl1', "detail_3");
/**
* 明细3需求数量
*/
const detail3NumFieldId3 = WfForm.convertFieldNameToId('sl', "detail_3");
/**
* 明细3bom编码
*/
const detail3BomFieldId = WfForm.convertFieldNameToId('bombm', "detail_3");
/**
* 明细1bom编码
*/
const detail1BomFieldId = WfForm.convertFieldNameToId('bombm', "detail_1");
/*
*已经选择的bom
*/
let choiceArr = new Set();
let updateNum = {};
const yjdhrq = WfForm.convertFieldNameToId('yjdhrq');
console.log('id ', yjdhrq)
// 明细到货日期
const detail1yjdhsj = WfForm.convertFieldNameToId('yjdhsj', "detail_2");
WfForm.bindFieldChangeEvent(yjdhrq, function (obj, id, value) {
initDeatail2Date(value);
});
WfForm.registerCheckEvent(WfForm.OPER_ADDROW + "2", function (callback) {
callback();
let value = WfForm.getFieldValue(yjdhrq);
initDeatail2Date(value);
});
WfForm.bindDetailFieldChangeEvent(detailBomField, function (id, rowIndex, value) {
if (!value) {
return;
}
if (choiceArr.has(value)) {
WfForm.showMessage('不能选择重复的bom请重新选择!');
setTimeout(() => {
WfForm.changeFieldValue(`${detailBomField}_${rowIndex}`, {value: '', specialobj: []});
}, 5);
}
initChoiceArr();
getBomArr();
});
// 数量变化自动计算
WfForm.bindDetailFieldChangeEvent(`${detail1NumFieldId},${detailBomField}`, function (id, rowIndex, value) {
let detail1RowArr = WfForm.getDetailAllRowIndexStr('detail_1').split(",");
console.log(detail1RowArr);
for (let i = 0; i < detail1RowArr.length; i++) {
let rowIndex = detail1RowArr[i];
if (rowIndex !== "") {
let num = WfForm.getFieldValue(`${detail1NumFieldId}_${rowIndex}`);
// bom编码
let bom = WfForm.getFieldValue(`${detail1BomFieldId}_${rowIndex}`);
setTimeout(() => {
computeNum(bom, num);
}, 500);
}
}
});
function initDeatail2Date(value) {
let detail2RowArr = WfForm.getDetailAllRowIndexStr('detail_2').split(",");
for (let i = 0; i < detail2RowArr.length; i++) {
let rowIndex = detail2RowArr[i];
if (rowIndex !== "") {
WfForm.changeFieldValue(`${detail1yjdhsj}_${rowIndex}`, {value: value});
}
}
}
/**
* 计算明细3数量
*/
function computeNum(detail1Bom, detail1Num) {
let detail3RowArr = WfForm.getDetailAllRowIndexStr('detail_3').split(",");
console.log(detail3RowArr);
for (let i = 0; i < detail3RowArr.length; i++) {
let rowIndex = detail3RowArr[i];
if (rowIndex !== "") {
// bom编码
let bom = WfForm.getFieldValue(`${detail3BomFieldId}_${rowIndex}`);
if (bom != detail1Bom) {
continue;
}
console.log('需要改变的index ', rowIndex)
WfForm.changeFieldValue(`${detail3NumFieldId}_${rowIndex}`, {value: detail1Num});
}
}
}
/**
* 初始化已经选择的数组
*/
function initChoiceArr() {
choiceArr = new Set();
let rowArr = WfForm.getDetailAllRowIndexStr('detail_1').split(",");
for (let i = 0; i < rowArr.length; i++) {
let rowIndex = rowArr[i];
if (rowIndex !== "") {
let bom = WfForm.getFieldValue(`${detailBomField}_${rowIndex}`);
// console.log('bom ', bom);
if (!bom) {
continue;
}
choiceArr.add(bom);
}
}
console.log('choiceArr ', choiceArr)
}
WfForm.registerCheckEvent(WfForm.OPER_DELROW + "1", function (callback) {
callback();
getBomArr();
initChoiceArr();
});
function getBomArr() {
let arr = [];
let rowArr = WfForm.getDetailAllRowIndexStr('detail_1').split(",");
for (let i = 0; i < rowArr.length; i++) {
let rowIndex = rowArr[i];
if (rowIndex !== "") {
arr.push(WfForm.getFieldValue(`${detailBomField}_${rowIndex}`));
}
}
let bom = new Set(arr);
let arr2 = [...bom];
let obj = {};
obj.value = arr2.join(',');
let specialobjArr = [];
for (let i = 0; i < arr2.length; i++) {
let obj = {};
obj.id = arr2[i];
obj.name = arr2[i];
specialobjArr.push(obj);
}
obj.specialobj = specialobjArr;
let val = WfForm.changeFieldValue(mainAttrField, obj);
if (!val) {
WfForm.delDetailRow("detail_3", "all");
}
console.log('主表辅助字段值 : ', WfForm.getFieldValue(mainAttrField));
}

View File

@ -51,6 +51,9 @@ function init(){
'computeDatePayType': computeDatePayType,
'paymentTypeGetValue': paymentTypeGetValue
}
addRowBack(3, obj);
changeDetailFieldReadOnly(detailTable, detailComPayDateId, detailPaymentTypeId, computeDatePayType)
// 主表字段发生变化
mainFieldChangeDetailCom(`${mainProjectId},${contractSignDateId}`, detailTable, obj);

View File

@ -52,6 +52,7 @@ function init(){
'computeDatePayType': computeDatePayType,
'paymentTypeGetValue': paymentTypeGetValue
}
addRowBack(2, obj);
changeDetailFieldReadOnly(detailTable, detail2ComPayDateId, detail2PaymentTypeId, computeDatePayType)
// 主表字段发生变化
mainFieldChangeDetailCom(mainProjectId, detailTable, obj);

View File

@ -535,7 +535,46 @@ $(() => {
callback()
})
})
/* ******************* 流程明细字段包含某个字符串时给某个字段赋值为某个东西end ******************* */
/* ******************* 流程明细字段包含某个字符串时给某个字段赋值为某个东西end ******************* */
/* ******************* 流程提交按钮触发流程抄送start ******************* */
$(() => {
let config = {
// 抄送人所在明细表编号1-明细1 2-明细2
detailNo: '1',
// 抄送人所在字段字段名
ccResourceField: '',
// 一级部门负责人字段名
firstLevelDepResponsibleField: ''
}
WfForm.registerCheckEvent(WfForm.OPER_SUBMIT, function (callback) {
$.ajax("/api/aiyh/pcn/cc-workflow/trigger", {
type: "POST",
data: JSON.stringify({
detailNo: config.detailNo,
requestId: WfForm.getBaseInfo().requestid,
ccResourceField: config.ccResourceField,
firstLevelDepResponsibleField: config.firstLevelDepResponsibleField
}),
headers: {
"Content-Type": "application/json"
},
complete: (res) => {
res.then(r => {
if (r && r.code === 200) {
callback();
}
})
}
})
});
})
/* ******************* 流程提交按钮触发流程抄送end ******************* */
/* ******************* 提交外出流程 ******************* */
(function start() {

View File

@ -0,0 +1 @@
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCa8TBiSrOPSgJER3nd+gW2eCoSjXHRVxEX54AdxzmtDe4Rn6OlvMVG1GLWfTnjdwbLTVeZUqjTpgZkCdGIp9njgjs6v6oQ7f8+DhQvByp6BSNXBHM+XH+YnmIohcQpnH7qvDT8l41Io2IVZbeNBWMlAtnz7laXWisYkYEDUm8HXOadKLkX+aqWdEYJHGy8zYN9ktNWH7P8BXBUAUd1vtTZhhE6BMd/O0WSqWhgpABbFZ8VKVT/5u4dlXUykKNbCKrsfXoiLE/7plbfHji02sUdaA1LAOF4QOaTePaGZu/55TWCYZPjWKrW2c0Gr8mS/1MQrg1zsWV2c59GqLNMWICtAgMBAAECggEAOS4thvi+j3DmqUAfj3YHybFLBZHBoVoaatH6jALMHDt50nMxt6aUv3D+EN4iEPoKPdkLLQA+Ye1xilW9SEt5s+aJ6UJ2hszuV35moHxqhqGCy0hPJ4KHbFF3NDE5lYm1pPdULqvXbiktt2vUc2y7jBsjSEx7FFwob2azUACKDRL+PkNGGcMmdMeCIHBcQf+j0CTY/VvsPGHqf53I/Ffe2KAE3Y0SugoIB5dqUE9VN5KGC01+X6hufaNUpPLYLbBiaI1eHVtMCHbGNmNnHuFgsEWT4ya4fw1rm9DLS8zJwDHkHmegE5ieqM7EzM2UIvKCN3TQJcy+Ssk3FX+KBFQqmQKBgQDaiC8QFqA7z8DY0K6lwj8PMiuNeu9APJuHLAhGdbDXjAKfdU1cNU4SHfsjjCU4Wymgp8QNrMD8WhardKHV+zr6B0mRMnUYOI6aoAg1+UcGoHYM2PEonZS+OtBHI68wDIsiKQ2Mybsl6GlxoLfo3YdlcclPFHNzXoVc8QFboN0TdwKBgQC1gerb6Anwlj6rJB9RCnoR/Jq5Lyh5wa1eL1C+gZSSM8Mwwxu3VpPohUMca7t1F1vmEDaf/Z2nsQ8IULnYkS94iGYooIcV2ffY5bagi/DkuTYfbf2QBWSZNTI1yHTWoaIXElRG0+svxgL6w98D3Y5lzIt0skz+/ZSGIdiLg8mt+wKBgQCBJCNzxXsxfWeAeWoMKMttJn/YXwLOGkLq0ZmeUeSMrH/MTdzGlfWp/S+xZRuFv1HNT/crAaEWQALPleAhfRLwOKg/9up9wsZ7GAFiLArOHrtEgluZXe5NsKHuuGbJ5U+/gzUvsvM2xq6xaIHmSiu+Rkzpv7MuRXhYYVAlHt4mpwKBgALOOEgf5Q9v8xYIH+fLxqlCg027ed+v67MZ/iCDtj0wSaMWUPZbgzvD246z55jevI/ozj9Y1zgBV58kSEsdq2MskI+uM4hV7yvOGS2QHDAc4MZJl/LC8pQfq2ADcjLjGrNKmDzkB62cXO1tW6Qep5XRPJKYMvJ6DvKn0UYOym5DAoGBALsEOPep1R8CBWCnni8igvbMudBwpzg5e9V6bu7p3MdADhGA/FMkCQgI2VH6fTufQsOA6rYi7YcdMS80r+p1/HMuVskOlqQfPDJ3OG0g0W8nwxf3XbIoEJcaAzLmqDOQMHfhmnoQsPlnCd7YRybbEEkEbKeRjyrDqhMSTSWC8lw4

View File

@ -0,0 +1 @@
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmvEwYkqzj0oCREd53foFtngqEo1x0VcRF+eAHcc5rQ3uEZ+jpbzFRtRi1n0543cGy01XmVKo06YGZAnRiKfZ44I7Or+qEO3/Pg4ULwcqegUjVwRzPlx/mJ5iKIXEKZx+6rw0/JeNSKNiFWW3jQVjJQLZ8+5Wl1orGJGBA1JvB1zmnSi5F/mqlnRGCRxsvM2DfZLTVh+z/AVwVAFHdb7U2YYROgTHfztFkqloYKQAWxWfFSlU/+buHZV1MpCjWwiq7H16IixP+6ZW3x44tNrFHWgNSwDheEDmk3j2hmbv+eU1gmGT41iq1tnNBq/Jkv9TEK4Nc7FldnOfRqizTFiArQIDAQAB

View File

@ -56,6 +56,12 @@
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!-- 图片efi信息识别ps贵酒-->
<dependency>
<groupId>com.drewnoakes</groupId>
<artifactId>metadata-extractor</artifactId>
<version>${metadata-extractor.version}</version>
</dependency>
<!-- 单元测试-->

View File

@ -732,7 +732,7 @@ public class Util extends weaver.general.Util {
StringBuilder buffer = new StringBuilder();
for (int i = 0, l = charArray.length; i < l; i++) {
// 判断当前字符是否是"_",如果跳出本次循环
if (charArray[i] == 95) {
if (charArray[i] == '_') {
underlineBefore = true;
} else if (underlineBefore) {
// 如果为true代表上次的字符是"_",当前字符需要转成大写
@ -763,10 +763,10 @@ public class Util extends weaver.general.Util {
for (int i = 0, l = charArray.length; i < l; i++) {
if (charArray[i] >= 65 && charArray[i] <= 90) {
if (i == 0) {
buffer.append(charArray[i] += 32);
buffer.append(Character.toLowerCase(charArray[i]));
continue;
}
buffer.append("_").append(charArray[i] += 32);
buffer.append("_").append(Character.toLowerCase(charArray[i]));
} else {
buffer.append(charArray[i]);
}
@ -2100,7 +2100,12 @@ public class Util extends weaver.general.Util {
String s;
for (Iterator<T> item = coll.iterator(); item.hasNext(); sb.append(s)) {
s = (String) item.next();
T value = item.next();
if (Objects.isNull(value)) {
s = "";
} else {
s = String.valueOf(value);
}
if (isFirst) {
isFirst = false;
} else {
@ -2111,6 +2116,38 @@ public class Util extends weaver.general.Util {
}
}
/**
* join
*
* @param coll
* @param split
* @return
*/
public static <T> String joinEach(T[] coll, String split) {
if (Objects.isNull(coll)) {
return "";
} else {
StringBuilder sb = new StringBuilder();
boolean isFirst = true;
String s;
for (Iterator<T> item = Arrays.stream(coll).iterator(); item.hasNext(); sb.append(s)) {
T value = item.next();
if (Objects.isNull(value)) {
s = "";
} else {
s = String.valueOf(value);
}
if (isFirst) {
isFirst = false;
} else {
sb.append(split);
}
}
return sb.toString();
}
}
/**
* 使
*
@ -3736,7 +3773,35 @@ public class Util extends weaver.general.Util {
return Util.getValueByKeyStr("main." + fieldInfo.getFieldName(), workflowData);
}
public static <K, V> Map<K, V> createFunctionMap() {
return null;
public static String getIpAddress(HttpServletRequest request) throws IOException {
// 获取请求主机IP地址,如果通过代理进来则透过防火墙获取真实IP地址
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} else if (ip.length() > 15) {
String[] ips = ip.split(",");
for (int index = 0; index < ips.length; index++) {
String strIp = ips[index];
if (!("unknown".equalsIgnoreCase(strIp))) {
ip = strIp;
break;
}
}
}
return ip;
}
}

View File

@ -18,7 +18,8 @@ public @interface Association {
String column();
String select();
String select() default "";
Id id();

View File

@ -0,0 +1,20 @@
package aiyh.utils.annotation.recordset;
import java.lang.annotation.*;
/**
* <h1></h1>
*
* <p>create: 2022-08-09 17:40</p>
*
* @author aiyh EBU7-dev-1
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface BatchDeleteOracle {
String value() default "";
// sql是否是在参数中
boolean custom() default false;
}

View File

@ -0,0 +1,20 @@
package aiyh.utils.annotation.recordset;
import java.lang.annotation.*;
/**
* <h1></h1>
*
* <p>create: 2022-08-09 17:40</p>
*
* @author aiyh EBU7-dev-1
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface BatchInsertOracle {
String value() default "";
// sql是否是在参数中
boolean custom() default false;
}

View File

@ -0,0 +1,20 @@
package aiyh.utils.annotation.recordset;
import java.lang.annotation.*;
/**
* <h1></h1>
*
* <p>create: 2022-08-09 17:40</p>
*
* @author aiyh EBU7-dev-1
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface BatchUpdateOracle {
String value() default "";
// sql是否是在参数中
boolean custom() default false;
}

View File

@ -0,0 +1,16 @@
package aiyh.utils.annotation.recordset;
import java.lang.annotation.*;
/**
* <h1>null</h1>
*
* <p>create: 2023/3/8 21:41</p>
*
* @author youHong.ai
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface CanBeNull {
}

View File

@ -17,7 +17,7 @@ public @interface CollectionMapping {
String property();
/** 数据库字段名 */
String column();
String column() default "";
/** 查询方法全限定类名 */
String select() default "";

View File

@ -0,0 +1,20 @@
package aiyh.utils.annotation.recordset;
import java.lang.annotation.*;
/**
* <h1></h1>
*
* <p>create: 2023/3/10 10:18</p>
*
* @author youHong.ai
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
@Documented
public @interface Column {
String value();
String oracle() default "";
}

View File

@ -0,0 +1,18 @@
package aiyh.utils.annotation.recordset;
import java.lang.annotation.*;
/**
* @author @author EBU7-dev1-ay
* create 2021/12/19 0019 15:08
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DeleteOracle {
String value() default "";
// sql是否是在参数中
boolean custom() default false;
}

View File

@ -0,0 +1,18 @@
package aiyh.utils.annotation.recordset;
import java.lang.annotation.*;
/**
* @author @author EBU7-dev1-ay
* create 2021/12/19 0019 15:08
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface InsertOracle {
String value() default "";
// sql是否是在参数中
boolean custom() default false;
}

View File

@ -11,7 +11,8 @@ import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Documented
public @interface Select {
String value() default "";
// sql是否是在参数中
boolean custom() default false;
String value() default "";
// sql是否是在参数中
boolean custom() default false;
}

View File

@ -0,0 +1,17 @@
package aiyh.utils.annotation.recordset;
import java.lang.annotation.*;
/**
* @author @author EBU7-dev1-ay
* create 2021/12/19 0019 15:08
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface SelectOracle {
String value() default "";
boolean custom() default false;
}

View File

@ -0,0 +1,18 @@
package aiyh.utils.annotation.recordset;
import java.lang.annotation.*;
/**
* @author @author EBU7-dev1-ay
* create 2021/12/19 0019 15:08
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface UpdateOracle {
String value() default "";
// sql是否是在参数中
boolean custom() default false;
}

View File

@ -1,5 +1,6 @@
package aiyh.utils.entity;
import aiyh.utils.annotation.recordset.SqlOracleDbFieldAnn;
import lombok.Data;
/**
@ -11,11 +12,33 @@ import lombok.Data;
@Data
public class DocImageInfo {
/** docId */
@SqlOracleDbFieldAnn("DOC_ID")
private Integer docId;
/** image id */
@SqlOracleDbFieldAnn("IMAGE_FILE_ID")
private Integer imageFileId;
/** 文件名称 */
@SqlOracleDbFieldAnn("IMAGE_FILE_NAME")
private String imageFileName;
/** 创建时间 */
@SqlOracleDbFieldAnn("DOC_CREATE_TIME")
private String docCreateTime;
/** 创建日期 */
@SqlOracleDbFieldAnn("DOC_CREATE_DATE")
private String docCreateDate;
/** 明细数据id */
@SqlOracleDbFieldAnn("ID")
private Integer id;
/** 其他id */
@SqlOracleDbFieldAnn("DETAIL_ID")
private Integer detailId;
/** 文件大小 */
@SqlOracleDbFieldAnn("FILE_SIZE")
private Integer fileSize;
/** 文件类型 */
@SqlOracleDbFieldAnn("DOC_FILE_TYPE")
private Integer docFileType;
}

View File

@ -6,7 +6,7 @@ import lombok.Setter;
import lombok.ToString;
/**
* <h1></h1>
* <h1></h1>
*
* <p>create: 2023/2/20 11:01</p>
*

View File

@ -0,0 +1,28 @@
package aiyh.utils.entity;
import aiyh.utils.annotation.recordset.SqlOracleDbFieldAnn;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* <h1></h1>
*
* <p>create: 2023/3/14 17:05</p>
*
* @author youHong.ai
*/
@Getter
@Setter
@ToString
public class ModelTableInfo {
/** id */
@SqlOracleDbFieldAnn("ID")
private String id;
@SqlOracleDbFieldAnn("INDEX_DESC")
private String indexDesc;
/** 字段表名 */
@SqlOracleDbFieldAnn("TABLE_NAME")
private String tableName;
}

View File

@ -3,7 +3,7 @@ package aiyh.utils.entity;
import lombok.Data;
/**
* <p></p>
* <p></p>
* <p>create 2022/6/10 21:21</p>
*
* @author ayh
@ -11,10 +11,10 @@ import lombok.Data;
@Data
public class SelectValueEntity {
private String id;
private String fieldname;
private String fieldlabel;
private String tablename;
private String selectname;
private Integer selectvalue;
private String id;
private String fieldname;
private String fieldlabel;
private String tablename;
private String selectname;
private Integer selectvalue;
}

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,6 @@ import weaver.file.ImageFileManager;
import weaver.system.SystemComInfo;
import java.io.*;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
@ -30,216 +29,216 @@ import java.util.UUID;
public class PdfUtil {
private static final Logger log = Util.getLogger("util_water_log");
private static final Logger log = Util.getLogger("util_water_log");
/**
*
*
* @param inputStream pdf
* @param keyword
* @return
*/
public static List<PdfPointItem> findKeywordPoints(InputStream inputStream, String keyword) {
PdfReader pdfReader = null;
try {
pdfReader = new PdfReader(inputStream);
} catch (IOException e) {
throw new CustomerException("读取pdf失败", e);
}
return getKeywordPoints(pdfReader, keyword);
}
/**
*
*
* @param inputStream pdf
* @param keyword
* @return
*/
public static List<PdfPointItem> findKeywordPoints(InputStream inputStream, String keyword) {
PdfReader pdfReader = null;
try {
pdfReader = new PdfReader(inputStream);
} catch (IOException e) {
throw new CustomerException("读取pdf失败", e);
}
return getKeywordPoints(pdfReader, keyword);
}
/**
*
*
* @param pdfReader pdf
* @param keyword
* @return
*/
private static List<PdfPointItem> getKeywordPoints(PdfReader pdfReader, String keyword) {
int totalPage = pdfReader.getNumberOfPages();
PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(pdfReader);
CustomerPdfRenderListener customerPdfRenderListener = new CustomerPdfRenderListener();
customerPdfRenderListener.setKeyWord(keyword);
customerPdfRenderListener.setTotalPage(totalPage);
for (int page = 1; page <= totalPage; page++) {
customerPdfRenderListener.setPage(page);
try {
pdfReaderContentParser.processContent(page, customerPdfRenderListener);
} catch (IOException e) {
throw new CustomerException("解析pdf失败", e);
}
}
pdfReader.close();
return customerPdfRenderListener.getPoints();
}
/**
*
*
* @param pdfReader pdf
* @param keyword
* @return
*/
private static List<PdfPointItem> getKeywordPoints(PdfReader pdfReader, String keyword) {
int totalPage = pdfReader.getNumberOfPages();
PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(pdfReader);
CustomerPdfRenderListener customerPdfRenderListener = new CustomerPdfRenderListener();
customerPdfRenderListener.setKeyWord(keyword);
customerPdfRenderListener.setTotalPage(totalPage);
for (int page = 1; page <= totalPage; page++) {
customerPdfRenderListener.setPage(page);
try {
pdfReaderContentParser.processContent(page, customerPdfRenderListener);
} catch (IOException e) {
throw new CustomerException("解析pdf失败", e);
}
}
pdfReader.close();
return customerPdfRenderListener.getPoints();
}
/**
*
*
* @param pdfImageFileId pdfid
* @param pictureInputStream
* @param keyword
* @param allKeyword
* @param opacity
* @param imageFitWidth
* @param imageFitHeight
* @param offsetX x
* @param offsetY y
* @return pdf
*/
public static int addPictureWater2pdfByKeyword(int pdfImageFileId,
InputStream pictureInputStream,
String keyword,
boolean allKeyword,
float opacity,
int imageFitWidth,
int imageFitHeight,
int offsetX,
int offsetY) {
ImageFileManager imageFileManager = new ImageFileManager();
imageFileManager.getImageFileInfoById(pdfImageFileId);
String imageFileName = imageFileManager.getImageFileName();
String suffix = imageFileName.substring(imageFileName.lastIndexOf(".") + 1);
if (!"pdf".equalsIgnoreCase(suffix)) {
throw new CustomerException("不支持的文件类型 " + suffix);
}
InputStream inputStream = ImageFileManager.getInputStreamById(pdfImageFileId);
List<PdfPointItem> keywordPoints = findKeywordPoints(inputStream, keyword);
PdfReader pdfReader = null;
Image image = null;
try {
byte[] imgb = org.apache.commons.io.IOUtils.toByteArray(pictureInputStream);
image = Image.getInstance(imgb);
} catch (Exception e) {
throw new CustomerException("获取水印图片失败!", e);
}
PdfGState gs = new PdfGState();
gs.setFillOpacity(opacity);
image.scaleToFit(imageFitWidth, imageFitHeight);
String createDir = FileUpload.getCreateDir(new SystemComInfo().getFilesystem()) + "tempfile" + File.separator;
/**
*
*
* @param pdfImageFileId pdfid
* @param pictureInputStream
* @param keyword
* @param allKeyword
* @param opacity
* @param imageFitWidth
* @param imageFitHeight
* @param offsetX x
* @param offsetY y
* @return pdf
*/
public static int addPictureWater2pdfByKeyword(int pdfImageFileId,
InputStream pictureInputStream,
String keyword,
boolean allKeyword,
float opacity,
int imageFitWidth,
int imageFitHeight,
int offsetX,
int offsetY) {
ImageFileManager imageFileManager = new ImageFileManager();
imageFileManager.getImageFileInfoById(pdfImageFileId);
String imageFileName = imageFileManager.getImageFileName();
String suffix = imageFileName.substring(imageFileName.lastIndexOf(".") + 1);
if (!"pdf".equalsIgnoreCase(suffix)) {
throw new CustomerException("不支持的文件类型 " + suffix);
}
InputStream inputStream = ImageFileManager.getInputStreamById(pdfImageFileId);
List<PdfPointItem> keywordPoints = findKeywordPoints(inputStream, keyword);
PdfReader pdfReader = null;
Image image = null;
try {
byte[] imgb = org.apache.commons.io.IOUtils.toByteArray(pictureInputStream);
image = Image.getInstance(imgb);
} catch (Exception e) {
throw new CustomerException("获取水印图片失败!", e);
}
PdfGState gs = new PdfGState();
gs.setFillOpacity(opacity);
image.scaleToFit(imageFitWidth, imageFitHeight);
String createDir = FileUpload.getCreateDir(new SystemComInfo().getFilesystem()) + "tempfile" + File.separator;
// 防止高并发下文件名重复导致文件覆盖的问题
String tempPath = createDir + imageFileName + System.currentTimeMillis() + UUID.randomUUID() + ".pdf";
File file = new File(tempPath);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
throw new CustomerException("创建临时文件失败!", e);
}
}
String tempPath = createDir + imageFileName + System.currentTimeMillis() + UUID.randomUUID() + ".pdf";
File file = new File(tempPath);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
throw new CustomerException("创建临时文件失败!", e);
}
}
// 输出到临时目录
FileOutputStream outputStreamTem;
try {
outputStreamTem = new FileOutputStream(URLDecoder.decode(tempPath, "utf-8"));
} catch (FileNotFoundException | UnsupportedEncodingException e) {
throw new CustomerException("创建临时文件流和路径转换失败!", e);
}
PdfStamper pdfStamper = null;
try {
inputStream = ImageFileManager.getInputStreamById(pdfImageFileId);
pdfReader = new PdfReader(inputStream);
pdfStamper = new PdfStamper(pdfReader, outputStreamTem);
} catch (IOException | DocumentException e) {
throw new CustomerException("读取pdf失败", e);
}
if (allKeyword) {
addPictureWater2pdfByKeywordAllKeyword(pdfStamper, keywordPoints, image, gs, offsetX, offsetY);
} else {
PdfPointItem keywordPoint = keywordPoints.get(0);
PdfContentByte overContent = pdfStamper.getOverContent(keywordPoint.getStartPage());
overContent.setGState(gs);
float absoluteX = keywordPoint.getStartPointX() + offsetX;
float absoluteY = keywordPoint.getStartPointY() + offsetY;
image.setAbsolutePosition(absoluteX, absoluteY);
try {
overContent.addImage(image);
} catch (DocumentException e) {
throw new CustomerException("添加水印图片失败!", e);
}
}
try {
pdfStamper.close();
outputStreamTem.close();
} catch (IOException | DocumentException e) {
e.printStackTrace();
log.error("关闭流失败!", e);
}
int imageFileId = -1;
InputStream waterPdf = null;
try {
waterPdf = new FileInputStream(tempPath);
} catch (FileNotFoundException e) {
throw new CustomerException("文件水印添加失败!", e);
}
imageFileId = Util.createFileByInputSteam(waterPdf, imageFileName);
try {
waterPdf.close();
Files.deleteIfExists(Paths.get(tempPath));
} catch (IOException e ){
e.printStackTrace();
}
return imageFileId;
}
FileOutputStream outputStreamTem;
try {
outputStreamTem = new FileOutputStream(tempPath);
} catch (FileNotFoundException e) {
throw new CustomerException("创建临时文件流和路径转换失败!", e);
}
PdfStamper pdfStamper = null;
try {
inputStream = ImageFileManager.getInputStreamById(pdfImageFileId);
pdfReader = new PdfReader(inputStream);
pdfStamper = new PdfStamper(pdfReader, outputStreamTem);
} catch (IOException | DocumentException e) {
throw new CustomerException("读取pdf失败", e);
}
if (allKeyword) {
addPictureWater2pdfByKeywordAllKeyword(pdfStamper, keywordPoints, image, gs, offsetX, offsetY);
} else {
PdfPointItem keywordPoint = keywordPoints.get(0);
PdfContentByte overContent = pdfStamper.getOverContent(keywordPoint.getStartPage());
overContent.setGState(gs);
float absoluteX = keywordPoint.getStartPointX() + offsetX;
float absoluteY = keywordPoint.getStartPointY() + offsetY;
image.setAbsolutePosition(absoluteX, absoluteY);
try {
overContent.addImage(image);
} catch (DocumentException e) {
throw new CustomerException("添加水印图片失败!", e);
}
}
try {
pdfStamper.close();
outputStreamTem.close();
} catch (IOException | DocumentException e) {
e.printStackTrace();
log.error("关闭流失败!", e);
}
int imageFileId = -1;
InputStream waterPdf = null;
try {
waterPdf = new FileInputStream(tempPath);
} catch (FileNotFoundException e) {
throw new CustomerException("文件水印添加失败!", e);
}
imageFileId = Util.createFileByInputSteam(waterPdf, imageFileName);
try {
waterPdf.close();
Files.deleteIfExists(Paths.get(tempPath));
} catch (IOException e) {
e.printStackTrace();
}
return imageFileId;
}
/**
*
*
* @param pdfImageFileId pdfid
* @param pictureImageFileId id
* @param keyword
* @param allKeyword
* @param opacity
* @param imageFitWidth
* @param imageFitHeight
* @param offsetX x
* @param offsetY y
* @return pdf
*/
public static int addPictureWater2pdfByKeyword(int pdfImageFileId,
int pictureImageFileId,
String keyword,
boolean allKeyword,
float opacity,
int imageFitWidth,
int imageFitHeight,
int offsetX,
int offsetY) {
InputStream pictureInputStream = ImageFileManager.getInputStreamById(pictureImageFileId);
return addPictureWater2pdfByKeyword(pdfImageFileId, pictureInputStream, keyword, allKeyword, opacity, imageFitWidth, imageFitHeight, offsetX, offsetY);
}
/**
*
*
* @param pdfImageFileId pdfid
* @param pictureImageFileId id
* @param keyword
* @param allKeyword
* @param opacity
* @param imageFitWidth
* @param imageFitHeight
* @param offsetX x
* @param offsetY y
* @return pdf
*/
public static int addPictureWater2pdfByKeyword(int pdfImageFileId,
int pictureImageFileId,
String keyword,
boolean allKeyword,
float opacity,
int imageFitWidth,
int imageFitHeight,
int offsetX,
int offsetY) {
InputStream pictureInputStream = ImageFileManager.getInputStreamById(pictureImageFileId);
return addPictureWater2pdfByKeyword(pdfImageFileId, pictureInputStream, keyword, allKeyword, opacity, imageFitWidth, imageFitHeight, offsetX, offsetY);
}
/**
*
*
* @param pdfStamper pdfStamper
* @param keywordPoints
* @param image
* @param gs
* @param offsetX X
* @param offsetY Y
*/
private static void addPictureWater2pdfByKeywordAllKeyword(PdfStamper pdfStamper,
List<PdfPointItem> keywordPoints,
Image image, PdfGState gs,
int offsetX, int offsetY) {
PdfContentByte overContent = null;
for (PdfPointItem keywordPoint : keywordPoints) {
overContent = pdfStamper.getOverContent(keywordPoint.getStartPage());
overContent.setGState(gs);
float absoluteX = keywordPoint.getStartPointX() + offsetX;
float absoluteY = keywordPoint.getStartPointY() + offsetY;
image.setAbsolutePosition(absoluteX, absoluteY);
try {
overContent.addImage(image);
} catch (DocumentException e) {
throw new CustomerException("添加水印图片失败!", e);
}
}
}
/**
*
*
* @param pdfStamper pdfStamper
* @param keywordPoints
* @param image
* @param gs
* @param offsetX X
* @param offsetY Y
*/
private static void addPictureWater2pdfByKeywordAllKeyword(PdfStamper pdfStamper,
List<PdfPointItem> keywordPoints,
Image image, PdfGState gs,
int offsetX, int offsetY) {
PdfContentByte overContent = null;
for (PdfPointItem keywordPoint : keywordPoints) {
overContent = pdfStamper.getOverContent(keywordPoint.getStartPage());
overContent.setGState(gs);
float absoluteX = keywordPoint.getStartPointX() + offsetX;
float absoluteY = keywordPoint.getStartPointY() + offsetY;
image.setAbsolutePosition(absoluteX, absoluteY);
try {
overContent.addImage(image);
} catch (DocumentException e) {
throw new CustomerException("添加水印图片失败!", e);
}
}
}
}

View File

@ -4,7 +4,6 @@ package aiyh.utils.httpUtil;
import aiyh.utils.Util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -136,11 +135,11 @@ public class ResponeVo implements HttpResponse {
} catch (JsonProcessingException ignored) {
try {
this.resultList = (List<Map>) JSONArray.parseArray(this.getEntityString(), Map.class);
} catch (JSONException e) {
Util.getLogger().error("Unable to convert the response result to array" + Util.getErrString(e));
} catch (Exception e) {
Util.getLogger().error("Unable to convert the response result to array");
}
} catch (Exception e) {
Util.getLogger().error("Unable to convert the response result to map or array" + Util.getErrString(e));
Util.getLogger().error("Unable to convert the response result to map or array");
}
}

View File

@ -86,6 +86,10 @@ public class HttpUtils {
}
public void setCredentialsProvider(CredentialsProvider credentialsProvider) {
this.credentialsProvider = credentialsProvider;
}
public HttpUtils(CredentialsProvider credentialsProvider) {
this.credentialsProvider = credentialsProvider;
}

View File

@ -1,10 +1,7 @@
package aiyh.utils.mapper;
import aiyh.utils.annotation.recordset.*;
import aiyh.utils.entity.DocImageInfo;
import aiyh.utils.entity.FieldViewInfo;
import aiyh.utils.entity.SelectValueEntity;
import aiyh.utils.entity.WorkflowNodeConfig;
import aiyh.utils.entity.*;
import java.util.List;
import java.util.Map;
@ -58,17 +55,31 @@ public interface UtilMapper {
String selectWorkfowMainTable(@ParamMapper("workflowId") String workflowId);
@Select("select id,docid doc_id,imagefileid image_file_id,imagefilename image_file_name from docimagefile where docid = #{docId}")
@Select("select di.id id,dc.id doc_id," +
"di.imagefileid image_file_id," +
"dc.DOCCREATEDATE doc_create_date,dc.DOCCREATETIME doc_create_time," +
"(case when imagefilename = '' or imagefilename is null then dc.DOCSUBJECT else imagefilename end) image_file_name " +
"from DocDetail dc " +
"left join docimagefile di on (dc.id = #{docId} and dc.id = di.docid) " +
"where dc.id = #{docId} ")
DocImageInfo selectDocImageInfo(@ParamMapper("docId") String docId);
@Select("select id,docid doc_id," +
"imagefileid image_file_id, docfiletype doc_file_type," +
"imagefilename image_file_name from docimagefile where docid in ($t{docIds})")
@Select("select di.id id,dc.id doc_id," +
"di.imagefileid image_file_id, di.docfiletype doc_file_type," +
"dc.DOCCREATEDATE doc_create_date,dc.DOCCREATETIME doc_create_time," +
"(case when imagefilename = '' or imagefilename is null then dc.DOCSUBJECT else imagefilename end) image_file_name " +
"from DocDetail dc " +
"left join docimagefile di on (dc.id in ($t{docIds}) and dc.id = di.docid )" +
"where dc.id in ($t{docIds})")
List<DocImageInfo> selectDocImageInfos(@ParamMapper("docIds") String docIds);
@Select("select id,docid doc_id,imagefileid image_file_id," +
"docfiletype doc_file_type," +
"imagefilename image_file_name from docimagefile where docid in (${docIds})")
@Select("select di.id id,dc.id doc_id," +
"di.imagefileid image_file_id, di.docfiletype doc_file_type," +
"dc.DOCCREATEDATE doc_create_date,dc.DOCCREATETIME doc_create_time," +
"(case when imagefilename = '' or imagefilename is null then dc.DOCSUBJECT else imagefilename end) image_file_name " +
"from DocDetail dc " +
"left join docimagefile di on (dc.id in ($t{docIds}) and dc.id = di.docid )" +
"where dc.id in ($t{docIds})")
List<DocImageInfo> selectDocImageInfos(@ParamMapper("docIds") String[] docIds);
@ -176,4 +187,14 @@ public interface UtilMapper {
" fieldhtmltype field_html_type\n" +
"from workflow_field_table_view where id = #{id}")
FieldViewInfo selectFieldInfo(Integer id);
/**
* <h2></h2>
*
* @param id id
* @return
*/
@Select("select id, tablename table_name, indexdesc index_desc from mode_bill_info_view where id = #{id}")
ModelTableInfo selectModelTableInfo(Integer id);
}

View File

@ -1,10 +1,12 @@
package aiyh.utils.recordset;
import aiyh.utils.Util;
import aiyh.utils.annotation.recordset.CanBeNull;
import weaver.conn.RecordSet;
import weaver.conn.RecordSetTrans;
import java.lang.reflect.Field;
import java.util.Objects;
/**
* <p>float</p>
@ -18,7 +20,12 @@ public class DoubleTypeHandler implements TypeHandler {
public Object getValue(RecordSet rs, String fieldName, Field declaredField) {
String string = Util.null2String(GetRsValueUtil.getRsValue(rs, fieldName, declaredField));
if ("".equals(string)) {
return null;
if (!Objects.isNull(declaredField)) {
if (declaredField.isAnnotationPresent(CanBeNull.class)) {
return null;
}
}
return 0.0D;
}
return Double.parseDouble(string);
}
@ -27,7 +34,12 @@ public class DoubleTypeHandler implements TypeHandler {
public Object getValue(RecordSet rs, int index, Field declaredField) {
String string = Util.null2String(rs.getString(index));
if ("".equals(string)) {
return null;
if (!Objects.isNull(declaredField)) {
if (declaredField.isAnnotationPresent(CanBeNull.class)) {
return null;
}
}
return 0.0D;
}
return Double.parseDouble(string);
}
@ -36,7 +48,12 @@ public class DoubleTypeHandler implements TypeHandler {
public Object getValue(RecordSetTrans rs, String fieldName, Field declaredField) {
String string = Util.null2String(GetRsValueUtil.getRsValue(rs, fieldName, declaredField));
if ("".equals(string)) {
return null;
if (!Objects.isNull(declaredField)) {
if (declaredField.isAnnotationPresent(CanBeNull.class)) {
return null;
}
}
return 0.0D;
}
return Double.parseDouble(string);
}
@ -45,7 +62,12 @@ public class DoubleTypeHandler implements TypeHandler {
public Object getValue(RecordSetTrans rs, int index, Field declaredField) {
String string = Util.null2String(rs.getString(index));
if ("".equals(string)) {
return null;
if (!Objects.isNull(declaredField)) {
if (declaredField.isAnnotationPresent(CanBeNull.class)) {
return null;
}
}
return 0.0D;
}
return Double.parseDouble(string);
}

View File

@ -1,10 +1,12 @@
package aiyh.utils.recordset;
import aiyh.utils.Util;
import aiyh.utils.annotation.recordset.CanBeNull;
import weaver.conn.RecordSet;
import weaver.conn.RecordSetTrans;
import java.lang.reflect.Field;
import java.util.Objects;
/**
* <p>float</p>
@ -18,7 +20,12 @@ public class FloatTypeHandler implements TypeHandler {
public Object getValue(RecordSet rs, String fieldName, Field declaredField) {
String string = Util.null2String(GetRsValueUtil.getRsValue(rs, fieldName, declaredField));
if ("".equals(string)) {
return null;
if (!Objects.isNull(declaredField)) {
if (declaredField.isAnnotationPresent(CanBeNull.class)) {
return null;
}
}
return 0.0F;
}
return Float.parseFloat(string);
}
@ -27,7 +34,12 @@ public class FloatTypeHandler implements TypeHandler {
public Object getValue(RecordSet rs, int index, Field declaredField) {
String string = Util.null2String(rs.getString(index), "0.0");
if ("".equals(string)) {
return null;
if (!Objects.isNull(declaredField)) {
if (declaredField.isAnnotationPresent(CanBeNull.class)) {
return null;
}
}
return 0.0F;
}
return Float.parseFloat(string);
}
@ -36,7 +48,12 @@ public class FloatTypeHandler implements TypeHandler {
public Object getValue(RecordSetTrans rs, String fieldName, Field declaredField) {
String string = Util.null2String(GetRsValueUtil.getRsValue(rs, fieldName, declaredField));
if ("".equals(string)) {
return null;
if (!Objects.isNull(declaredField)) {
if (declaredField.isAnnotationPresent(CanBeNull.class)) {
return null;
}
}
return 0.0F;
}
return Float.parseFloat(string);
}
@ -45,7 +62,12 @@ public class FloatTypeHandler implements TypeHandler {
public Object getValue(RecordSetTrans rs, int index, Field declaredField) {
String string = Util.null2String(rs.getString(index));
if ("".equals(string)) {
return null;
if (!Objects.isNull(declaredField)) {
if (declaredField.isAnnotationPresent(CanBeNull.class)) {
return null;
}
}
return 0.0F;
}
return Float.parseFloat(string);
}

View File

@ -0,0 +1,38 @@
package aiyh.utils.recordset;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.parser.ParserException;
import weaver.conn.RecordSet;
import java.util.Objects;
/**
* <h1>sql</h1>
*
* <p>create: 2023/3/5 11:45</p>
*
* @author youHong.ai
*/
public class FormatSqlUtil {
private static String dbType = null;
private static RecordSet recordSet = null;
public static String formatSql(String sql) {
if (Objects.isNull(FormatSqlUtil.dbType)) {
if (recordSet == null) {
recordSet = new RecordSet();
}
FormatSqlUtil.dbType = recordSet.getDBType();
}
try {
return SQLUtils.format(sql, dbType);
} catch (ParserException e) {
return toSqlString(sql);
}
}
private static String toSqlString(String sql) {
return sql;
}
}

View File

@ -1,10 +1,12 @@
package aiyh.utils.recordset;
import aiyh.utils.Util;
import aiyh.utils.annotation.recordset.CanBeNull;
import weaver.conn.RecordSet;
import weaver.conn.RecordSetTrans;
import java.lang.reflect.Field;
import java.util.Objects;
/**
* @author EBU7-dev1-ayh create 2021/12/21 0021 13:10
@ -16,7 +18,10 @@ public class IntegerTypeHandler implements TypeHandler {
public Object getValue(RecordSet rs, String fieldName, Field declaredField) {
String string = Util.null2String(GetRsValueUtil.getRsValue(rs, fieldName, declaredField));
if ("".equals(string)) {
return null;
if (declaredField.isAnnotationPresent(CanBeNull.class)) {
return null;
}
return -1;
}
if (string.contains(".")) {
string = string.substring(0, string.indexOf("."));
@ -28,7 +33,12 @@ public class IntegerTypeHandler implements TypeHandler {
public Object getValue(RecordSet rs, int index, Field declaredField) {
String string = Util.null2String(rs.getString(index));
if ("".equals(string)) {
return null;
if (!Objects.isNull(declaredField)) {
if (declaredField.isAnnotationPresent(CanBeNull.class)) {
return null;
}
}
return -1;
}
if (string.contains(".")) {
string = string.substring(0, string.indexOf("."));
@ -40,7 +50,12 @@ public class IntegerTypeHandler implements TypeHandler {
public Object getValue(RecordSetTrans rs, String fieldName, Field declaredField) {
String string = Util.null2String(GetRsValueUtil.getRsValue(rs, fieldName, declaredField));
if ("".equals(string)) {
return null;
if (!Objects.isNull(declaredField)) {
if (declaredField.isAnnotationPresent(CanBeNull.class)) {
return null;
}
}
return -1;
}
if (string.contains(".")) {
string = string.substring(0, string.indexOf("."));
@ -52,7 +67,12 @@ public class IntegerTypeHandler implements TypeHandler {
public Object getValue(RecordSetTrans rs, int index, Field declaredField) {
String string = Util.null2String(rs.getString(index));
if ("".equals(string)) {
return null;
if (!Objects.isNull(declaredField)) {
if (declaredField.isAnnotationPresent(CanBeNull.class)) {
return null;
}
}
return -1;
}
if (string.contains(".")) {
string = string.substring(0, string.indexOf("."));

View File

@ -8,6 +8,7 @@ import aiyh.utils.sqlUtil.sqlResult.impl.BatchSqlResultImpl;
import aiyh.utils.sqlUtil.sqlResult.impl.PrepSqlResultImpl;
import weaver.conn.RecordSet;
import weaver.conn.RecordSetTrans;
import weaver.conn.constant.DBConstant;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
@ -59,6 +60,146 @@ public class RecordsetUtil implements InvocationHandler {
return invokeRsTrans(proxy, method, args, name);
}
private Object invokeDefault(int type, String sql, boolean custom, RecordSet rs, Method method, Object[] args) {
SqlHandler sqlHandler = new SqlHandler();
ResultMapper resultMapper = new ResultMapper();
PrepSqlResultImpl handler = sqlHandler.handler(sql, custom, method, args);
String invokeMethod = method.getDeclaringClass().getName() + ":" + method.getName() + " : ";
switch (type) {
case 1: {
if (!handler.getSqlStr().trim().toLowerCase().startsWith("select ")) {
throw new CustomerException("The sql statement does not match, the @Select annotation can only execute the select statement, please check whether the sql statement matches!");
}
Util.getLogger(SQL_LOG).info(invokeMethod + handler);
if (handler.getArgs().isEmpty()) {
rs.executeQuery(handler.getSqlStr());
} else {
rs.executeQuery(handler.getSqlStr(), handler.getArgs());
}
return resultMapper.mapperResult(rs, method, method.getReturnType(), this);
}
case 2: {
if (!handler.getSqlStr().trim().toLowerCase().startsWith("update ")) {
throw new CustomerException("The sql statement does not match, the @Update annotation can only execute the update statement, please check whether the sql statement matches!");
}
Util.getLogger(SQL_LOG).info(invokeMethod + handler);
Class<?> returnType = method.getReturnType();
boolean b;
if (handler.getArgs().isEmpty()) {
b = rs.executeUpdate(handler.getSqlStr());
} else {
b = rs.executeUpdate(handler.getSqlStr(), handler.getArgs());
}
if (returnType.equals(void.class)) {
return null;
}
if (returnType.equals(int.class) || returnType.equals(Integer.class)) {
if (b) {
return 1;
} else {
return 0;
}
}
if (returnType.equals(boolean.class) || returnType.equals(Boolean.class)) {
return b;
}
}
case 3: {
if (!handler.getSqlStr().trim().toLowerCase().startsWith("insert ")) {
throw new CustomerException("The sql statement does not match, the @Insert annotation can only execute the insert statement, please check whether the sql statement matches!");
}
Util.getLogger(SQL_LOG).info(invokeMethod + handler);
Class<?> returnType = method.getReturnType();
boolean b;
if (handler.getArgs().isEmpty()) {
b = rs.executeUpdate(handler.getSqlStr());
} else {
b = rs.executeUpdate(handler.getSqlStr(), handler.getArgs());
}
if (returnType.equals(void.class)) {
return null;
}
if (returnType.equals(boolean.class) || returnType.equals(Boolean.class)) {
return b;
}
}
case 4: {
if (!handler.getSqlStr().trim().toLowerCase().startsWith("delete ")) {
throw new CustomerException("The sql statement does not match, the @Delete annotation can only execute the delete statement, please check whether the sql statement matches!");
}
Util.getLogger(SQL_LOG).info(invokeMethod + handler);
Class<?> returnType = method.getReturnType();
boolean b;
if (handler.getArgs().isEmpty()) {
b = rs.executeUpdate(handler.getSqlStr());
} else {
b = rs.executeUpdate(handler.getSqlStr(), handler.getArgs());
}
if (returnType.equals(void.class)) {
return null;
}
if (returnType.equals(boolean.class) || returnType.equals(Boolean.class)) {
return b;
}
}
case 5: {
Class<?> returnType = method.getReturnType();
BatchSqlResultImpl batchSqlResult = sqlHandler.handlerBatch(sql, custom, method, args);
Util.getLogger(SQL_LOG).info(invokeMethod + batchSqlResult.toString());
if (batchSqlResult.getBatchList().isEmpty()) {
throw new CustomerException("execute batch sql error , batch sql args is empty!");
}
if (!batchSqlResult.getSqlStr().trim().toLowerCase().startsWith("insert ")) {
throw new CustomerException("The sql statement does not match, the @Insert annotation can only execute the insert statement, please check whether the sql statement matches!");
}
boolean b = rs.executeBatchSql(batchSqlResult.getSqlStr(), batchSqlResult.getBatchList());
if (returnType.equals(void.class)) {
return null;
}
if (returnType.equals(boolean.class) || returnType.equals(Boolean.class)) {
return b;
}
}
case 6: {
Class<?> returnType = method.getReturnType();
BatchSqlResultImpl batchSqlResult = sqlHandler.handlerBatch(sql, custom, method, args);
Util.getLogger(SQL_LOG).info(invokeMethod + batchSqlResult.toString());
if (batchSqlResult.getBatchList().isEmpty()) {
throw new CustomerException("execute batch sql error , batch sql args is empty!");
}
if (!batchSqlResult.getSqlStr().trim().toLowerCase().startsWith("update ")) {
throw new CustomerException("The sql statement does not match, the @Update annotation can only execute the update statement, please check whether the sql statement matches!");
}
boolean b = rs.executeBatchSql(batchSqlResult.getSqlStr(), batchSqlResult.getBatchList());
if (returnType.equals(void.class)) {
return null;
}
if (returnType.equals(boolean.class) || returnType.equals(Boolean.class)) {
return b;
}
}
case 7: {
Class<?> returnType = method.getReturnType();
BatchSqlResultImpl batchSqlResult = sqlHandler.handlerBatch(sql, custom, method, args);
Util.getLogger(SQL_LOG).info(invokeMethod + batchSqlResult.toString());
if (batchSqlResult.getBatchList().isEmpty()) {
throw new CustomerException("execute batch sql error , batch sql args is empty!");
}
if (!batchSqlResult.getSqlStr().trim().toLowerCase().startsWith("delete ")) {
throw new CustomerException("The sql statement does not match, the @Delete annotation can only execute the delete statement, please check whether the sql statement matches!");
}
boolean b = rs.executeBatchSql(batchSqlResult.getSqlStr(), batchSqlResult.getBatchList());
if (returnType.equals(void.class)) {
return null;
}
if (returnType.equals(boolean.class) || returnType.equals(Boolean.class)) {
return b;
}
}
default:
throw new CustomerException("不支持的sql注解类型 " + type);
}
}
private Object invokeRs(Object proxy, Method method, Object[] args, String name) {
String mapperKey = method.getDeclaringClass().getName();
@ -71,177 +212,100 @@ public class RecordsetUtil implements InvocationHandler {
rs = rsManager.getRs(mapperKey);
}
SqlHandler sqlHandler = new SqlHandler();
ResultMapper resultMapper = new ResultMapper();
if (DBConstant.DB_TYPE_ORACLE.equals(rs.getDBType())) {
SelectOracle selectOracle = method.getAnnotation(SelectOracle.class);
if (selectOracle != null) {
String sql = selectOracle.value();
boolean custom = selectOracle.custom();
return invokeDefault(1, sql, custom, rs, method, args);
}
UpdateOracle updateOracle = method.getAnnotation(UpdateOracle.class);
if (updateOracle != null) {
String sql = updateOracle.value();
boolean custom = updateOracle.custom();
return invokeDefault(2, sql, custom, rs, method, args);
}
InsertOracle insertOracle = method.getAnnotation(InsertOracle.class);
if (insertOracle != null) {
String sql = insertOracle.value();
boolean custom = insertOracle.custom();
return invokeDefault(3, sql, custom, rs, method, args);
}
DeleteOracle deleteOracle = method.getAnnotation(DeleteOracle.class);
if (deleteOracle != null) {
String sql = deleteOracle.value();
boolean custom = deleteOracle.custom();
return invokeDefault(4, sql, custom, rs, method, args);
}
BatchInsertOracle batchInsertOracle = method.getAnnotation(BatchInsertOracle.class);
if (batchInsertOracle != null) {
String sql = batchInsertOracle.value();
boolean custom = batchInsertOracle.custom();
return invokeDefault(5, sql, custom, rs, method, args);
}
BatchUpdateOracle batchUpdateOracle = method.getAnnotation(BatchUpdateOracle.class);
if (batchUpdateOracle != null) {
String sql = batchUpdateOracle.value();
boolean custom = batchUpdateOracle.custom();
return invokeDefault(6, sql, custom, rs, method, args);
}
BatchDeleteOracle batchDeleteOracle = method.getAnnotation(BatchDeleteOracle.class);
if (batchDeleteOracle != null) {
String sql = batchDeleteOracle.value();
boolean custom = batchDeleteOracle.custom();
return invokeDefault(7, sql, custom, rs, method, args);
}
}
Select select = method.getAnnotation(Select.class);
if (select != null) {
// 查询
String sql = select.value();
boolean custom = select.custom();
PrepSqlResultImpl handler = sqlHandler.handler(sql, custom, method, args);
if (!handler.getSqlStr().trim().toLowerCase().startsWith("select ")) {
throw new CustomerException("The sql statement does not match, the @Select annotation can only execute the select statement, please check whether the sql statement matches!");
}
Util.getLogger(SQL_LOG).info("解析sql===>" + handler);
if (handler.getArgs().isEmpty()) {
rs.executeQuery(handler.getSqlStr());
} else {
rs.executeQuery(handler.getSqlStr(), handler.getArgs());
}
return resultMapper.mapperResult(rs, method, method.getReturnType(), this);
return invokeDefault(1, sql, custom, rs, method, args);
}
Update update = method.getAnnotation(Update.class);
if (update != null) {
// 查询
String sql = update.value();
boolean custom = update.custom();
PrepSqlResultImpl handler = sqlHandler.handler(sql, custom, method, args);
if (!handler.getSqlStr().trim().toLowerCase().startsWith("update ")) {
throw new CustomerException("The sql statement does not match, the @Update annotation can only execute the update statement, please check whether the sql statement matches!");
}
Util.getLogger(SQL_LOG).info(handler.toString());
Class<?> returnType = method.getReturnType();
boolean b;
if (handler.getArgs().isEmpty()) {
b = rs.executeUpdate(handler.getSqlStr());
} else {
b = rs.executeUpdate(handler.getSqlStr(), handler.getArgs());
}
if (returnType.equals(void.class)) {
return null;
}
if (returnType.equals(int.class) || returnType.equals(Integer.class)) {
if (b) {
return 1;
} else {
return 0;
}
}
if (returnType.equals(boolean.class) || returnType.equals(Boolean.class)) {
return b;
}
return invokeDefault(2, sql, custom, rs, method, args);
}
Insert insert = method.getAnnotation(Insert.class);
if (insert != null) {
// 查询
String sql = insert.value();
boolean custom = insert.custom();
PrepSqlResultImpl handler = sqlHandler.handler(sql, custom, method, args);
if (!handler.getSqlStr().trim().toLowerCase().startsWith("insert ")) {
throw new CustomerException("The sql statement does not match, the @Insert annotation can only execute the insert statement, please check whether the sql statement matches!");
}
Util.getLogger(SQL_LOG).info(handler.toString());
Class<?> returnType = method.getReturnType();
boolean b;
if (handler.getArgs().isEmpty()) {
b = rs.executeUpdate(handler.getSqlStr());
} else {
b = rs.executeUpdate(handler.getSqlStr(), handler.getArgs());
}
if (returnType.equals(void.class)) {
return null;
}
if (returnType.equals(boolean.class) || returnType.equals(Boolean.class)) {
return b;
}
return invokeDefault(3, sql, custom, rs, method, args);
}
Delete delete = method.getAnnotation(Delete.class);
if (delete != null) {
// 查询
String sql = delete.value();
boolean custom = delete.custom();
PrepSqlResultImpl handler = sqlHandler.handler(sql, custom, method, args);
if (!handler.getSqlStr().trim().toLowerCase().startsWith("delete ")) {
throw new CustomerException("The sql statement does not match, the @Delete annotation can only execute the delete statement, please check whether the sql statement matches!");
}
Util.getLogger(SQL_LOG).info(handler.toString());
Class<?> returnType = method.getReturnType();
boolean b;
if (handler.getArgs().isEmpty()) {
b = rs.executeUpdate(handler.getSqlStr());
} else {
b = rs.executeUpdate(handler.getSqlStr(), handler.getArgs());
}
if (returnType.equals(void.class)) {
return null;
}
if (returnType.equals(boolean.class) || returnType.equals(Boolean.class)) {
return b;
}
return invokeDefault(4, sql, custom, rs, method, args);
}
boolean hasBatchInsert = method.isAnnotationPresent(BatchInsert.class);
if (hasBatchInsert) {
BatchInsert batchInsert = method.getAnnotation(BatchInsert.class);
BatchInsert batchInsert = method.getAnnotation(BatchInsert.class);
if (batchInsert != null) {
String sql = batchInsert.value();
Class<?> returnType = method.getReturnType();
boolean custom = batchInsert.custom();
BatchSqlResultImpl batchSqlResult = sqlHandler.handlerBatch(sql, custom, method, args);
Util.getLogger(SQL_LOG).info(batchSqlResult.toString());
if (batchSqlResult.getBatchList().isEmpty()) {
throw new CustomerException("execute batch sql error , batch sql args is empty!");
}
if (!batchSqlResult.getSqlStr().trim().toLowerCase().startsWith("insert ")) {
throw new CustomerException("The sql statement does not match, the @Insert annotation can only execute the insert statement, please check whether the sql statement matches!");
}
boolean b = rs.executeBatchSql(batchSqlResult.getSqlStr(), batchSqlResult.getBatchList());
if (returnType.equals(void.class)) {
return null;
}
if (returnType.equals(boolean.class) || returnType.equals(Boolean.class)) {
return b;
}
return invokeDefault(5, sql, custom, rs, method, args);
}
boolean hasBatchUpdate = method.isAnnotationPresent(BatchUpdate.class);
if (hasBatchUpdate) {
BatchUpdate batchUpdate = method.getAnnotation(BatchUpdate.class);
BatchUpdate batchUpdate = method.getAnnotation(BatchUpdate.class);
if (batchUpdate != null) {
String sql = batchUpdate.value();
Class<?> returnType = method.getReturnType();
boolean custom = batchUpdate.custom();
BatchSqlResultImpl batchSqlResult = sqlHandler.handlerBatch(sql, custom, method, args);
Util.getLogger(SQL_LOG).info(batchSqlResult.toString());
if (batchSqlResult.getBatchList().isEmpty()) {
throw new CustomerException("execute batch sql error , batch sql args is empty!");
}
if (!batchSqlResult.getSqlStr().trim().toLowerCase().startsWith("update ")) {
throw new CustomerException("The sql statement does not match, the @Update annotation can only execute the update statement, please check whether the sql statement matches!");
}
boolean b = rs.executeBatchSql(batchSqlResult.getSqlStr(), batchSqlResult.getBatchList());
if (returnType.equals(void.class)) {
return null;
}
if (returnType.equals(boolean.class) || returnType.equals(Boolean.class)) {
return b;
}
return invokeDefault(6, sql, custom, rs, method, args);
}
boolean hasBatchDelete = method.isAnnotationPresent(BatchDelete.class);
if (hasBatchDelete) {
BatchDelete batchDelete = method.getAnnotation(BatchDelete.class);
BatchDelete batchDelete = method.getAnnotation(BatchDelete.class);
if (batchDelete != null) {
String sql = batchDelete.value();
Class<?> returnType = method.getReturnType();
boolean custom = batchDelete.custom();
BatchSqlResultImpl batchSqlResult = sqlHandler.handlerBatch(sql, custom, method, args);
Util.getLogger(SQL_LOG).info(batchSqlResult.toString());
if (batchSqlResult.getBatchList().isEmpty()) {
throw new CustomerException("execute batch sql error , batch sql args is empty!");
}
if (!batchSqlResult.getSqlStr().trim().toLowerCase().startsWith("delete ")) {
throw new CustomerException("The sql statement does not match, the @Delete annotation can only execute the delete statement, please check whether the sql statement matches!");
}
boolean b = rs.executeBatchSql(batchSqlResult.getSqlStr(), batchSqlResult.getBatchList());
if (returnType.equals(void.class)) {
return null;
}
if (returnType.equals(boolean.class) || returnType.equals(Boolean.class)) {
return b;
}
return invokeDefault(7, sql, custom, rs, method, args);
}
throw new CustomerException("该方法没有添加注解!请检查是否正确添加注解!@Select、@Update、@Insert、@Delete、@BatchUpdate、@BatchInsert、@BatchDelete");
}
private Object invokeRsTrans(Object proxy, Method method, Object[] args, String name) {
String mapperKey = method.getDeclaringClass().getName();
String invokeMethod = method.getDeclaringClass().getName() + ":" + method.getName() + " : ";
if (!"".equals(name) && null != name) {
mapperKey += "." + name;
}
@ -261,7 +325,7 @@ public class RecordsetUtil implements InvocationHandler {
if (!handler.getSqlStr().trim().toLowerCase().startsWith("select ")) {
throw new CustomerException("The sql statement does not match, the @Select annotation can only execute the select statement, please check whether the sql statement matches!");
}
Util.getLogger(SQL_LOG).info("解析sql===>" + handler);
Util.getLogger(SQL_LOG).info(invokeMethod + handler);
try {
if (handler.getArgs().isEmpty()) {
rs.executeQuery(handler.getSqlStr());
@ -284,7 +348,7 @@ public class RecordsetUtil implements InvocationHandler {
if (!handler.getSqlStr().trim().toLowerCase().startsWith("update ")) {
throw new CustomerException("The sql statement does not match, the @Update annotation can only execute the update statement, please check whether the sql statement matches!");
}
Util.getLogger(SQL_LOG).info(handler.toString());
Util.getLogger(SQL_LOG).info(invokeMethod + handler);
Class<?> returnType = method.getReturnType();
boolean b;
try {
@ -320,7 +384,7 @@ public class RecordsetUtil implements InvocationHandler {
if (!handler.getSqlStr().trim().toLowerCase().startsWith("insert ")) {
throw new CustomerException("The sql statement does not match, the @Insert annotation can only execute the insert statement, please check whether the sql statement matches!");
}
Util.getLogger(SQL_LOG).info(handler.toString());
Util.getLogger(SQL_LOG).info(invokeMethod + handler);
Class<?> returnType = method.getReturnType();
boolean b;
try {
@ -349,7 +413,7 @@ public class RecordsetUtil implements InvocationHandler {
if (!handler.getSqlStr().trim().toLowerCase().startsWith("delete ")) {
throw new CustomerException("The sql statement does not match, the @Delete annotation can only execute the delete statement, please check whether the sql statement matches!");
}
Util.getLogger(SQL_LOG).info(handler.toString());
Util.getLogger(SQL_LOG).info(invokeMethod + handler);
Class<?> returnType = method.getReturnType();
boolean b;
try {
@ -376,7 +440,7 @@ public class RecordsetUtil implements InvocationHandler {
Class<?> returnType = method.getReturnType();
boolean custom = batchInsert.custom();
BatchSqlResultImpl batchSqlResult = sqlHandler.handlerBatch(sql, custom, method, args);
Util.getLogger(SQL_LOG).info(batchSqlResult.toString());
Util.getLogger(SQL_LOG).info(invokeMethod + batchSqlResult.toString());
List<List> batchList = batchSqlResult.getBatchList();
if (batchList.isEmpty()) {
throw new CustomerException("execute batch sql error , batch sql args is empty!");
@ -415,7 +479,7 @@ public class RecordsetUtil implements InvocationHandler {
Class<?> returnType = method.getReturnType();
boolean custom = batchUpdate.custom();
BatchSqlResultImpl batchSqlResult = sqlHandler.handlerBatch(sql, custom, method, args);
Util.getLogger(SQL_LOG).info(batchSqlResult.toString());
Util.getLogger(SQL_LOG).info(invokeMethod + batchSqlResult.toString());
if (batchSqlResult.getBatchList().isEmpty()) {
throw new CustomerException("execute batch sql error , batch sql args is empty!");
}
@ -456,7 +520,7 @@ public class RecordsetUtil implements InvocationHandler {
Class<?> returnType = method.getReturnType();
boolean custom = batchDelete.custom();
BatchSqlResultImpl batchSqlResult = sqlHandler.handlerBatch(sql, custom, method, args);
Util.getLogger(SQL_LOG).info(batchSqlResult.toString());
Util.getLogger(SQL_LOG).info(invokeMethod + batchSqlResult.toString());
if (batchSqlResult.getBatchList().isEmpty()) {
throw new CustomerException("execute batch sql error , batch sql args is empty!");
}

View File

@ -41,7 +41,7 @@ public class ResultMapper {
typeHandler.put(Boolean.class, new BooleanTypeHandler());
typeHandler.put(boolean.class, new BooleanTypeHandler());
typeHandler.put(Date.class, new DataTypeHandler());
typeHandler.put(Float.class, new FloatTypeHandler());
typeHandler.put(float.class, new FloatTypeHandler());
typeHandler.put(Float.class, new FloatTypeHandler());
typeHandler.put(double.class, new DoubleTypeHandler());
typeHandler.put(Double.class, new DoubleTypeHandler());
@ -319,8 +319,12 @@ public class ResultMapper {
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getInt(i + 1));
continue;
}
if (DBConstant.DB_TYPE_ORACLE.equals(rs.getDBType())) {
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getInt(i + 1));
}
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getInt(i + 1));
((Map<? super Object, ? super Object>) o).put(columnName[i].toUpperCase(), rs.getInt(i + 1));
((Map<? super Object, ? super Object>) o).put(columnName[i], rs.getInt(i + 1));
continue;
}
if ("FLOAT".equalsIgnoreCase(columnType) || "DOUBLE".equalsIgnoreCase(columnType) || "DECIMAL".equalsIgnoreCase(columnType)) {
@ -328,16 +332,24 @@ public class ResultMapper {
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getFloat(i + 1));
continue;
}
if (DBConstant.DB_TYPE_ORACLE.equals(rs.getDBType())) {
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getFloat(i + 1));
}
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getFloat(i + 1));
((Map<? super Object, ? super Object>) o).put(columnName[i].toUpperCase(), rs.getFloat(i + 1));
((Map<? super Object, ? super Object>) o).put(columnName[i], rs.getFloat(i + 1));
continue;
}
if (enable) {
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getString(i + 1));
continue;
}
if (DBConstant.DB_TYPE_ORACLE.equals(rs.getDBType())) {
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getString(i + 1));
}
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getString(i + 1));
((Map<? super Object, ? super Object>) o).put(columnName[i].toUpperCase(), rs.getString(i + 1));
((Map<? super Object, ? super Object>) o).put(columnName[i], rs.getString(i + 1));
continue;
}
return o;
@ -386,7 +398,9 @@ public class ResultMapper {
} else {
value = ResultMapper.typeHandler.get(propertyType) == null ? null : ResultMapper.typeHandler.get(propertyType).getValue(rs, fieldName, declaredField);
}
propertyDescriptor.getWriteMethod().invoke(o, value);
if (!Objects.isNull(value)) {
propertyDescriptor.getWriteMethod().invoke(o, value);
}
}
} catch (Exception e) {
@ -449,8 +463,12 @@ public class ResultMapper {
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getInt(i + 1));
continue;
}
if (DBConstant.DB_TYPE_ORACLE.equals(rs.getDBType())) {
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getInt(i + 1));
}
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getInt(i + 1));
((Map<? super Object, ? super Object>) o).put(columnName[i].toUpperCase(), rs.getInt(i + 1));
((Map<? super Object, ? super Object>) o).put(columnName[i], rs.getInt(i + 1));
continue;
}
if ("FLOAT".equalsIgnoreCase(columnType) || "DOUBLE".equalsIgnoreCase(columnType) || "DECIMAL".equalsIgnoreCase(columnType)) {
@ -458,8 +476,12 @@ public class ResultMapper {
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getFloat(i + 1));
continue;
}
if (DBConstant.DB_TYPE_ORACLE.equals(rs.getDBType())) {
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getFloat(i + 1));
}
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getFloat(i + 1));
((Map<? super Object, ? super Object>) o).put(columnName[i].toUpperCase(), rs.getFloat(i + 1));
((Map<? super Object, ? super Object>) o).put(columnName[i], rs.getFloat(i + 1));
continue;
}
if (method.isAnnotationPresent(Associations.class)) {
@ -488,8 +510,12 @@ public class ResultMapper {
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getString(i + 1));
continue;
}
if (DBConstant.DB_TYPE_ORACLE.equals(rs.getDBType())) {
((Map<? super Object, ? super Object>) o).put(Util.toCamelCase(columnName[i]), rs.getString(i + 1));
}
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getString(i + 1));
((Map<? super Object, ? super Object>) o).put(columnName[i].toUpperCase(), rs.getString(i + 1));
((Map<? super Object, ? super Object>) o).put(columnName[i], rs.getString(i + 1));
}
return o;
}
@ -528,6 +554,7 @@ public class ResultMapper {
Object value = null;
String fieldName = propertyDescriptor.getName();
Field declaredField = o.getClass().getDeclaredField(fieldName);
if (Strings.isNullOrEmpty(fieldName)) {
fieldName = propertyDescriptor.getDisplayName();
}
@ -536,7 +563,20 @@ public class ResultMapper {
if (association != null) {
if (association.property().equals(fieldName)) {
Object cassociationValue = association(rs, association, method);
propertyDescriptor.getWriteMethod().invoke(o, cassociationValue);
if (cassociationValue == null) {
continue;
}
if (paramType.containsKey(declaredField.getType())) {
cassociationValue = paramType.get(declaredField.getType()).apply(String.valueOf(cassociationValue));
}
try {
propertyDescriptor.getWriteMethod().invoke(o, cassociationValue);
} catch (Exception e) {
Util.getLogger().error("实体数据写入报错:" + fieldName + " => " + value);
if (value != null) {
Util.getLogger().error("查询数据类型: " + value.getClass());
}
}
continue;
}
}
@ -546,21 +586,37 @@ public class ResultMapper {
if (collectionMapping != null) {
if (fieldName.equals(collectionMapping.property()) && !"".equals(collectionMapping.property())) {
Object collection = collection(rs, collectionMapping, method);
propertyDescriptor.getWriteMethod().invoke(o, collection);
try {
propertyDescriptor.getWriteMethod().invoke(o, collection);
} catch (Exception e) {
Util.getLogger().error("实体数据写入报错:" + fieldName + " => " + value);
if (value != null) {
Util.getLogger().error("查询数据类型: " + value.getClass());
}
}
continue;
}
}
}
Field declaredField = o.getClass().getDeclaredField(fieldName);
TypeHandler typeHandler = ResultMapper.typeHandler.get(propertyType);
if (enable) {
value = ResultMapper.typeHandler.get(propertyType) == null ? null : ResultMapper.typeHandler.get(propertyType).getValue(rs, Util.toUnderlineCase(fieldName), declaredField);
value = typeHandler == null ? null : typeHandler.getValue(rs, Util.toUnderlineCase(fieldName), declaredField);
} else {
value = ResultMapper.typeHandler.get(propertyType) == null ? null : ResultMapper.typeHandler.get(propertyType).getValue(rs, fieldName, declaredField);
value = typeHandler == null ? null : typeHandler.getValue(rs, fieldName, declaredField);
}
propertyDescriptor.getWriteMethod().invoke(o, value);
try {
if (!Objects.isNull(value)) {
propertyDescriptor.getWriteMethod().invoke(o, value);
}
} catch (Exception e) {
Util.getLogger().error("实体数据写入报错:" + fieldName + " => " + value);
if (value != null) {
Util.getLogger().error("查询数据类型: " + value.getClass());
}
throw e;
}
}
} catch (Exception e) {
Util.getLogger().error("报错了,写入数据到实体类报错!\n" + Util.getErrString(e));
throw new CustomerException(e.getMessage(), e);
@ -607,6 +663,9 @@ public class ResultMapper {
Id id = annotation.id();
String column = annotation.column();
String columnValue = rs.getString(column);
if (Objects.isNull(columnValue) || "".equals(columnValue)) {
columnValue = rs.getString(column.toUpperCase());
}
if (Objects.isNull(columnValue) || "".equals(columnValue)) {
return null;
}
@ -665,6 +724,9 @@ public class ResultMapper {
Id id = annotation.id();
String column = annotation.column();
String columnValue = rs.getString(column);
if (Objects.isNull(columnValue) || "".equals(columnValue)) {
columnValue = rs.getString(column.toUpperCase());
}
if (Objects.isNull(columnValue) || "".equals(columnValue)) {
return null;
}

View File

@ -1,5 +1,7 @@
package aiyh.utils.sqlUtil.sqlResult.impl;
import aiyh.utils.recordset.FormatSqlUtil;
import java.util.List;
/**
@ -10,27 +12,27 @@ import java.util.List;
public class BatchSqlResultImpl implements aiyh.utils.sqlUtil.sqlResult.SqlResult {
private final String sqlStr;
private final List<List> batchList;
private final String sqlStr;
private final List<List> batchList;
public BatchSqlResultImpl(String sqlStr, List<List> batchList) {
this.sqlStr = sqlStr;
this.batchList = batchList;
}
public BatchSqlResultImpl(String sqlStr, List<List> batchList) {
this.sqlStr = sqlStr;
this.batchList = batchList;
}
public String getSqlStr() {
return sqlStr;
}
public String getSqlStr() {
return sqlStr;
}
public List<List> getBatchList() {
return batchList;
}
public List<List> getBatchList() {
return batchList;
}
@Override
public String toString() {
return "BatchSqlResultImpl{" +
"sqlStr='" + sqlStr + '\'' +
", batchList=" + batchList +
'}';
}
@Override
public String toString() {
return "BatchSqlResultImpl{" +
"sqlStr='\n" + FormatSqlUtil.formatSql(sqlStr) + "\n'" +
", batchList=" + batchList +
'}';
}
}

View File

@ -1,5 +1,6 @@
package aiyh.utils.sqlUtil.sqlResult.impl;
import aiyh.utils.recordset.FormatSqlUtil;
import aiyh.utils.sqlUtil.sqlResult.SqlResult;
import java.util.List;
@ -28,11 +29,11 @@ public class PrepSqlResultImpl implements SqlResult {
return args;
}
@Override
public String toString() {
return "PrepSqlResultImpl{" +
"sqlStr='" + sqlStr + '\'' +
", args=" + args +
'}';
}
@Override
public String toString() {
return "PrepSqlResultImpl{" +
"sqlStr='\n" + FormatSqlUtil.formatSql(sqlStr) + "\n'" +
", args=" + args +
'}';
}
}

View File

@ -0,0 +1,168 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.annotation.scanner.AnnotationScanner;
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.map.MapUtil;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* {@link AnnotationSynthesizer}
*
* @author huangchengxing
*/
public abstract class AbstractAnnotationSynthesizer<T> implements AnnotationSynthesizer {
/**
*
*/
protected final T source;
/**
*
*/
protected final Map<Class<? extends Annotation>, SynthesizedAnnotation> synthesizedAnnotationMap;
/**
*
*/
private final Map<Class<? extends Annotation>, Annotation> synthesizedProxyAnnotations;
/**
*
*/
protected final SynthesizedAnnotationSelector annotationSelector;
/**
*
*/
protected final Collection<SynthesizedAnnotationPostProcessor> postProcessors;
/**
*
*/
protected final AnnotationScanner annotationScanner;
/**
*
*
* @param source
* @param annotationSelector
* @param annotationPostProcessors
* @param annotationScanner
*/
protected AbstractAnnotationSynthesizer(
T source,
SynthesizedAnnotationSelector annotationSelector,
Collection<SynthesizedAnnotationPostProcessor> annotationPostProcessors,
AnnotationScanner annotationScanner) {
Assert.notNull(source, "source must not null");
Assert.notNull(annotationSelector, "annotationSelector must not null");
Assert.notNull(annotationPostProcessors, "annotationPostProcessors must not null");
Assert.notNull(annotationPostProcessors, "annotationScanner must not null");
this.source = source;
this.annotationSelector = annotationSelector;
this.annotationScanner = annotationScanner;
this.postProcessors = CollUtil.unmodifiable(
CollUtil.sort(annotationPostProcessors, Comparator.comparing(SynthesizedAnnotationPostProcessor::order))
);
this.synthesizedProxyAnnotations = new LinkedHashMap<>();
this.synthesizedAnnotationMap = MapUtil.unmodifiable(loadAnnotations());
annotationPostProcessors.forEach(processor ->
synthesizedAnnotationMap.values().forEach(synthesized -> processor.process(synthesized, this))
);
}
/**
*
*
* @return
*/
protected abstract Map<Class<? extends Annotation>, SynthesizedAnnotation> loadAnnotations();
/**
*
*
* @param annotationType
* @param annotation
* @param <A>
* @return
*/
protected abstract <A extends Annotation> A synthesize(Class<A> annotationType, SynthesizedAnnotation annotation);
/**
*
*
* @return
*/
@Override
public T getSource() {
return source;
}
/**
*
*
* @return
*/
@Override
public SynthesizedAnnotationSelector getAnnotationSelector() {
return annotationSelector;
}
/**
*
*
* @return
*/
@Override
public Collection<SynthesizedAnnotationPostProcessor> getAnnotationPostProcessors() {
return postProcessors;
}
/**
*
*
* @param annotationType
* @return
*/
@Override
public SynthesizedAnnotation getSynthesizedAnnotation(Class<?> annotationType) {
return synthesizedAnnotationMap.get(annotationType);
}
/**
*
*
* @return
*/
@Override
public Map<Class<? extends Annotation>, SynthesizedAnnotation> getAllSynthesizedAnnotation() {
return synthesizedAnnotationMap;
}
/**
*
*
* @param annotationType
* @param <A>
* @return
*/
@SuppressWarnings("unchecked")
@Override
public <A extends Annotation> A synthesize(Class<A> annotationType) {
return (A)synthesizedProxyAnnotations.computeIfAbsent(annotationType, type -> {
final SynthesizedAnnotation synthesizedAnnotation = synthesizedAnnotationMap.get(annotationType);
return ObjectUtil.isNull(synthesizedAnnotation) ?
null : synthesize(annotationType, synthesizedAnnotation);
});
}
}

View File

@ -0,0 +1,163 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.lang.Opt;
import aiyh.utils.tool.cn.hutool.core.util.ArrayUtil;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
/**
* {@link SynthesizedAnnotationPostProcessor}
* {@link Link}
*
* @author huangchengxing
* @see MirrorLinkAnnotationPostProcessor
* @see AliasLinkAnnotationPostProcessor
*/
public abstract class AbstractLinkAnnotationPostProcessor implements SynthesizedAnnotationPostProcessor {
/**
* {@link Link}{@link Link#type()}{@link #processTypes()}
* {@link Link}{@link SynthesizedAggregateAnnotation}
*
* {@link #processLinkedAttribute}
*
* @param synthesizedAnnotation
* @param synthesizer
*/
@Override
public void process(SynthesizedAnnotation synthesizedAnnotation, AnnotationSynthesizer synthesizer) {
final Map<String, AnnotationAttribute> attributeMap = new HashMap<>(synthesizedAnnotation.getAttributes());
attributeMap.forEach((originalAttributeName, originalAttribute) -> {
// 获取注解
final Link link = getLinkAnnotation(originalAttribute, processTypes());
if (ObjectUtil.isNull(link)) {
return;
}
// 获取注解属性
final SynthesizedAnnotation linkedAnnotation = getLinkedAnnotation(link, synthesizer, synthesizedAnnotation.annotationType());
if (ObjectUtil.isNull(linkedAnnotation)) {
return;
}
final AnnotationAttribute linkedAttribute = linkedAnnotation.getAttributes().get(link.attribute());
// 处理
processLinkedAttribute(
synthesizer, link,
synthesizedAnnotation, synthesizedAnnotation.getAttributes().get(originalAttributeName),
linkedAnnotation, linkedAttribute
);
});
}
// =========================== 抽象方法 ===========================
/**
* {@link Link}{@link Link#type()}
*
* @return {@link RelationType}
*/
protected abstract RelationType[] processTypes();
/**
*
*
* @param synthesizer
* @param annotation {@code originalAttribute}{@link Link}
* @param originalAnnotation {@link SynthesizedAnnotation}
* @param originalAttribute {@code originalAnnotation}
* @param linkedAnnotation {@link Link}
* @param linkedAttribute {@link Link}{@code originalAnnotation}
*/
protected abstract void processLinkedAttribute(
AnnotationSynthesizer synthesizer, Link annotation,
SynthesizedAnnotation originalAnnotation, AnnotationAttribute originalAttribute,
SynthesizedAnnotation linkedAnnotation, AnnotationAttribute linkedAttribute
);
// =========================== @Link注解的处理 ===========================
/**
* {@link Link}
*
* @param attribute
* @param relationTypes
* @return
*/
protected Link getLinkAnnotation(AnnotationAttribute attribute, RelationType... relationTypes) {
return Opt.ofNullable(attribute)
.map(t -> AnnotationUtil.getSynthesizedAnnotation(attribute.getAttribute(), Link.class))
.filter(a -> ArrayUtil.contains(relationTypes, a.type()))
.get();
}
/**
* {@link Link#type()}
*
* @param annotation {@link Link}
* @param synthesizer
* @param defaultType
* @return {@link SynthesizedAnnotation}
*/
protected SynthesizedAnnotation getLinkedAnnotation(Link annotation, AnnotationSynthesizer synthesizer, Class<? extends Annotation> defaultType) {
final Class<?> targetAnnotationType = getLinkedAnnotationType(annotation, defaultType);
return synthesizer.getSynthesizedAnnotation(targetAnnotationType);
}
/**
* {@link Link#annotation()}{@code Annotation#getClass()}{@code defaultType}
* {@link Link#annotation()}
*
* @param annotation {@link Link}
* @param defaultType
* @return
*/
protected Class<?> getLinkedAnnotationType(Link annotation, Class<?> defaultType) {
return ObjectUtil.equals(annotation.annotation(), Annotation.class) ?
defaultType : annotation.annotation();
}
// =========================== 注解属性的校验 ===========================
/**
*
*
* @param original
* @param alias
*/
protected void checkAttributeType(AnnotationAttribute original, AnnotationAttribute alias) {
Assert.equals(
original.getAttributeType(), alias.getAttributeType(),
"return type of the linked attribute [{}] is inconsistent with the original [{}]",
original.getAttribute(), alias.getAttribute()
);
}
/**
* {@link Link}
*
* @param original {@link Link}
* @param linked {@link Link}
*/
protected void checkLinkedSelf(AnnotationAttribute original, AnnotationAttribute linked) {
boolean linkSelf = (original == linked) || ObjectUtil.equals(original.getAttribute(), linked.getAttribute());
Assert.isFalse(linkSelf, "cannot link self [{}]", original.getAttribute());
}
/**
* {@link Link}
*
* @param original {@link Link}
* @param linkedAttribute {@link Link}
* @param annotation {@link Link}
*/
protected void checkLinkedAttributeNotNull(AnnotationAttribute original, AnnotationAttribute linkedAttribute, Link annotation) {
Assert.notNull(linkedAttribute, "cannot find linked attribute [{}] of original [{}] in [{}]",
original.getAttribute(), annotation.attribute(),
getLinkedAnnotationType(annotation, original.getAnnotationType())
);
}
}

View File

@ -0,0 +1,71 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* {@link WrappedAnnotationAttribute}
*
* @author huangchengxing
* @see ForceAliasedAnnotationAttribute
* @see AliasedAnnotationAttribute
* @see MirroredAnnotationAttribute
*/
public abstract class AbstractWrappedAnnotationAttribute implements WrappedAnnotationAttribute {
protected final AnnotationAttribute original;
protected final AnnotationAttribute linked;
protected AbstractWrappedAnnotationAttribute(AnnotationAttribute original, AnnotationAttribute linked) {
Assert.notNull(original, "target must not null");
Assert.notNull(linked, "linked must not null");
this.original = original;
this.linked = linked;
}
@Override
public AnnotationAttribute getOriginal() {
return original;
}
@Override
public AnnotationAttribute getLinked() {
return linked;
}
@Override
public AnnotationAttribute getNonWrappedOriginal() {
AnnotationAttribute curr = null;
AnnotationAttribute next = original;
while (next != null) {
curr = next;
next = next.isWrapped() ? ((WrappedAnnotationAttribute)curr).getOriginal() : null;
}
return curr;
}
@Override
public Collection<AnnotationAttribute> getAllLinkedNonWrappedAttributes() {
List<AnnotationAttribute> leafAttributes = new ArrayList<>();
collectLeafAttribute(this, leafAttributes);
return leafAttributes;
}
private void collectLeafAttribute(AnnotationAttribute curr, List<AnnotationAttribute> leafAttributes) {
if (ObjectUtil.isNull(curr)) {
return;
}
if (!curr.isWrapped()) {
leafAttributes.add(curr);
return;
}
WrappedAnnotationAttribute wrappedAttribute = (WrappedAnnotationAttribute)curr;
collectLeafAttribute(wrappedAttribute.getOriginal(), leafAttributes);
collectLeafAttribute(wrappedAttribute.getLinked(), leafAttributes);
}
}

View File

@ -0,0 +1,27 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import java.lang.annotation.Annotation;
/**
*
*
* @author huangchengxing
*/
public interface AggregateAnnotation extends Annotation {
/**
*
*
* @param annotationType
* @return
*/
boolean isAnnotationPresent(Class<? extends Annotation> annotationType);
/**
*
*
* @return
*/
Annotation[] getAnnotations();
}

View File

@ -0,0 +1,26 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 使BeanBeanMap
*
* @author Looly
* @since 5.1.1
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface Alias {
/**
* 使
*
* @return
*/
String value();
}

View File

@ -0,0 +1,66 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.lang.Opt;
import aiyh.utils.tool.cn.hutool.core.map.ForestMap;
import aiyh.utils.tool.cn.hutool.core.map.LinkedForestMap;
import aiyh.utils.tool.cn.hutool.core.map.TreeEntry;
import aiyh.utils.tool.cn.hutool.core.util.ClassUtil;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.util.Map;
/**
* <p>{@link Alias}<br>
* {@link Alias}
* {@link ForceAliasedAnnotationAttribute}
*
* @author huangchengxing
* @see Alias
* @see ForceAliasedAnnotationAttribute
*/
public class AliasAnnotationPostProcessor implements SynthesizedAnnotationPostProcessor {
@Override
public int order() {
return Integer.MIN_VALUE;
}
@Override
public void process(SynthesizedAnnotation synthesizedAnnotation, AnnotationSynthesizer synthesizer) {
final Map<String, AnnotationAttribute> attributeMap = synthesizedAnnotation.getAttributes();
// 记录别名与属性的关系
final ForestMap<String, AnnotationAttribute> attributeAliasMappings = new LinkedForestMap<>(false);
attributeMap.forEach((attributeName, attribute) -> {
final String alias = Opt.ofNullable(attribute.getAnnotation(Alias.class))
.map(Alias::value)
.orElse(null);
if (ObjectUtil.isNull(alias)) {
return;
}
final AnnotationAttribute aliasAttribute = attributeMap.get(alias);
Assert.notNull(aliasAttribute, "no method for alias: [{}]", alias);
attributeAliasMappings.putLinkedNodes(alias, aliasAttribute, attributeName, attribute);
});
// 处理别名
attributeMap.forEach((attributeName, attribute) -> {
final AnnotationAttribute resolvedAttribute = Opt.ofNullable(attributeName)
.map(attributeAliasMappings::getRootNode)
.map(TreeEntry::getValue)
.orElse(attribute);
Assert.isTrue(
ObjectUtil.isNull(resolvedAttribute)
|| ClassUtil.isAssignable(attribute.getAttributeType(), resolvedAttribute.getAttributeType()),
"return type of the root alias method [{}] is inconsistent with the original [{}]",
resolvedAttribute.getClass(), attribute.getAttributeType()
);
if (attribute != resolvedAttribute) {
attributeMap.put(attributeName, new ForceAliasedAnnotationAttribute(attribute, resolvedAttribute));
}
});
synthesizedAnnotation.setAttributes(attributeMap);
}
}

View File

@ -0,0 +1,39 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import java.lang.annotation.*;
/**
* <p>{@link Link}
* <ul>
* <li></li>
* <li></li>
* </ul>
* <b>{@link Link}{@link ForceAliasFor}{@link MirrorFor}使</b>
*
* @author huangchengxing
* @see Link
* @see RelationType#ALIAS_FOR
*/
@Link(type = RelationType.ALIAS_FOR)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface AliasFor {
/**
*
*
* @return
*/
@Link(annotation = Link.class, attribute = "annotation", type = RelationType.FORCE_ALIAS_FOR)
Class<? extends Annotation> annotation() default Annotation.class;
/**
* {@link #annotation()}
*
* @return
*/
@Link(annotation = Link.class, attribute = "attribute", type = RelationType.FORCE_ALIAS_FOR)
String attribute() default "";
}

View File

@ -0,0 +1,126 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.lang.Opt;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.util.function.BinaryOperator;
/**
* <p>{@link Link}{@link Link#type()}
* {@link RelationType#ALIAS_FOR}{@link RelationType#FORCE_ALIAS_FOR}<br>
* {@link Link}
* {@link AliasedAnnotationAttribute}{@link ForceAliasedAnnotationAttribute}
*
* @author huangchengxing
* @see RelationType#ALIAS_FOR
* @see AliasedAnnotationAttribute
* @see RelationType#FORCE_ALIAS_FOR
* @see ForceAliasedAnnotationAttribute
*/
public class AliasLinkAnnotationPostProcessor extends AbstractLinkAnnotationPostProcessor {
private static final RelationType[] PROCESSED_RELATION_TYPES = new RelationType[]{ RelationType.ALIAS_FOR, RelationType.FORCE_ALIAS_FOR };
@Override
public int order() {
return Integer.MIN_VALUE + 2;
}
/**
* {@link Link#type()}{@link RelationType#ALIAS_FOR}{@link RelationType#FORCE_ALIAS_FOR}
*
* @return {@link RelationType#ALIAS_FOR}{@link RelationType#FORCE_ALIAS_FOR}
*/
@Override
protected RelationType[] processTypes() {
return PROCESSED_RELATION_TYPES;
}
/**
* {@link Link}{@link Link#type()}
* {@link RelationType#ALIAS_FOR}{@link RelationType#FORCE_ALIAS_FOR}
* {@link AliasedAnnotationAttribute}{@link ForceAliasedAnnotationAttribute}
*
*
* @param synthesizer
* @param annotation {@code originalAttribute}{@link Link}
* @param originalAnnotation {@link SynthesizedAnnotation}
* @param originalAttribute {@code originalAnnotation}
* @param linkedAnnotation {@link Link}
* @param linkedAttribute {@link Link}{@code originalAnnotation}
*/
@Override
protected void processLinkedAttribute(
AnnotationSynthesizer synthesizer, Link annotation,
SynthesizedAnnotation originalAnnotation, AnnotationAttribute originalAttribute,
SynthesizedAnnotation linkedAnnotation, AnnotationAttribute linkedAttribute) {
// 校验别名关系
checkAliasRelation(annotation, originalAttribute, linkedAttribute);
// 处理aliasFor类型的关系
if (RelationType.ALIAS_FOR.equals(annotation.type())) {
wrappingLinkedAttribute(synthesizer, originalAttribute, linkedAttribute, AliasedAnnotationAttribute::new);
return;
}
// 处理forceAliasFor类型的关系
wrappingLinkedAttribute(synthesizer, originalAttribute, linkedAttribute, ForceAliasedAnnotationAttribute::new);
}
/**
*
*/
private void wrappingLinkedAttribute(
AnnotationSynthesizer synthesizer, AnnotationAttribute originalAttribute, AnnotationAttribute aliasAttribute, BinaryOperator<AnnotationAttribute> wrapping) {
// 不是包装属性
if (!aliasAttribute.isWrapped()) {
processAttribute(synthesizer, originalAttribute, aliasAttribute, wrapping);
return;
}
// 是包装属性
final AbstractWrappedAnnotationAttribute wrapper = (AbstractWrappedAnnotationAttribute)aliasAttribute;
wrapper.getAllLinkedNonWrappedAttributes().forEach(
t -> processAttribute(synthesizer, originalAttribute, t, wrapping)
);
}
/**
*
*/
private void processAttribute(
AnnotationSynthesizer synthesizer, AnnotationAttribute originalAttribute,
AnnotationAttribute target, BinaryOperator<AnnotationAttribute> wrapping) {
Opt.ofNullable(target.getAnnotationType())
.map(synthesizer::getSynthesizedAnnotation)
.ifPresent(t -> t.replaceAttribute(target.getAttributeName(), old -> wrapping.apply(old, originalAttribute)));
}
/**
*
*/
private void checkAliasRelation(Link annotation, AnnotationAttribute originalAttribute, AnnotationAttribute linkedAttribute) {
checkLinkedAttributeNotNull(originalAttribute, linkedAttribute, annotation);
checkAttributeType(originalAttribute, linkedAttribute);
checkCircularDependency(originalAttribute, linkedAttribute);
}
/**
*
*/
private void checkCircularDependency(AnnotationAttribute original, AnnotationAttribute alias) {
checkLinkedSelf(original, alias);
Link annotation = getLinkAnnotation(alias, RelationType.ALIAS_FOR, RelationType.FORCE_ALIAS_FOR);
if (ObjectUtil.isNull(annotation)) {
return;
}
final Class<?> aliasAnnotationType = getLinkedAnnotationType(annotation, alias.getAnnotationType());
if (ObjectUtil.notEqual(aliasAnnotationType, original.getAnnotationType())) {
return;
}
Assert.notEquals(
annotation.attribute(), original.getAttributeName(),
"circular reference between the alias attribute [{}] and the original attribute [{}]",
alias.getAttribute(), original.getAttribute()
);
}
}

View File

@ -0,0 +1,36 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
/**
* <p>
*
*
* @author huangchengxing
* @see AliasLinkAnnotationPostProcessor
* @see RelationType#ALIAS_FOR
*/
public class AliasedAnnotationAttribute extends AbstractWrappedAnnotationAttribute {
protected AliasedAnnotationAttribute(AnnotationAttribute origin, AnnotationAttribute linked) {
super(origin, linked);
}
/**
* {@link #linked}{@link #original}{@link #linked}
*
* @return
*/
@Override
public Object getValue() {
return linked.isValueEquivalentToDefaultValue() ? super.getValue() : linked.getValue();
}
/**
* {@link #original}{@link #linked}{@code true}
*
* @return
*/
@Override
public boolean isValueEquivalentToDefaultValue() {
return linked.isValueEquivalentToDefaultValue() && original.isValueEquivalentToDefaultValue();
}
}

View File

@ -0,0 +1,104 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.util.ReflectUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
* <p>{@link Method}<br>
* {@link SynthesizedAggregateAnnotation}
* {@link SynthesizedAnnotation}
* 使
*
* <p>{@link SynthesizedAnnotationPostProcessor}
*
* @author huangchengxing
* @see SynthesizedAnnotationPostProcessor
* @see WrappedAnnotationAttribute
* @see CacheableAnnotationAttribute
* @see AbstractWrappedAnnotationAttribute
* @see ForceAliasedAnnotationAttribute
* @see AliasedAnnotationAttribute
* @see MirroredAnnotationAttribute
*/
public interface AnnotationAttribute {
/**
*
*
* @return
*/
Annotation getAnnotation();
/**
*
*
* @return
*/
Method getAttribute();
/**
*
*
* @return
*/
default Class<?> getAnnotationType() {
return getAttribute().getDeclaringClass();
}
/**
*
*
* @return
*/
default String getAttributeName() {
return getAttribute().getName();
}
/**
*
*
* @return
*/
default Object getValue() {
return ReflectUtil.invoke(getAnnotation(), getAttribute());
}
/**
*
*
* @return
*/
boolean isValueEquivalentToDefaultValue();
/**
*
*
* @return
*/
default Class<?> getAttributeType() {
return getAttribute().getReturnType();
}
/**
*
*
* @param <T>
* @param annotationType
* @return
*/
default <T extends Annotation> T getAnnotation(Class<T> annotationType) {
return getAttribute().getAnnotation(annotationType);
}
/**
* {@link WrappedAnnotationAttribute}
*
* @return boolean
*/
default boolean isWrapped() {
return false;
}
}

View File

@ -0,0 +1,18 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
/**
*
*/
@FunctionalInterface
public interface AnnotationAttributeValueProvider {
/**
*
*
* @param attributeName
* @param attributeType
* @return
*/
Object getAttributeValue(String attributeName, Class<?> attributeType);
}

View File

@ -0,0 +1,88 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.util.ReflectUtil;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* <br>
* {@link Alias}
*
* @param <T>
* @since 5.7.23
*/
public class AnnotationProxy<T extends Annotation> implements Annotation, InvocationHandler, Serializable {
private static final long serialVersionUID = 1L;
private final T annotation;
private final Class<T> type;
private final Map<String, Object> attributes;
/**
*
*
* @param annotation
*/
public AnnotationProxy(T annotation) {
this.annotation = annotation;
//noinspection unchecked
this.type = (Class<T>) annotation.annotationType();
this.attributes = initAttributes();
}
@Override
public Class<? extends Annotation> annotationType() {
return type;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 注解别名
Alias alias = method.getAnnotation(Alias.class);
if(null != alias){
final String name = alias.value();
if(StrUtil.isNotBlank(name)){
if(false == attributes.containsKey(name)){
throw new IllegalArgumentException(StrUtil.format("No method for alias: [{}]", name));
}
return attributes.get(name);
}
}
final Object value = attributes.get(method.getName());
if (value != null) {
return value;
}
return method.invoke(this, args);
}
/**
* <br>
* attributes
*
* @return
*/
private Map<String, Object> initAttributes() {
final Method[] methods = ReflectUtil.getMethods(this.type);
final Map<String, Object> attributes = new HashMap<>(methods.length, 1);
for (Method method : methods) {
// 跳过匿名内部类自动生成的方法
if (method.isSynthetic()) {
continue;
}
attributes.put(method.getName(), ReflectUtil.invoke(this.annotation, method));
}
return attributes;
}
}

View File

@ -0,0 +1,77 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Map;
/**
* <p>{@link #getSource()}
*
*
* <p>
* 使{@link SynthesizedAnnotationSelector}
* {@link SynthesizedAnnotation}
* {@link SynthesizedAggregateAnnotation}<br>
* {@link SynthesizedAnnotationSelector}
*
*
* <p>
* {@link SynthesizedAnnotationPostProcessor}
*
* {@link Link}<br>
* {@link SynthesizedAnnotationPostProcessor}
*
*
* <p>使{@link #synthesize(Class)}
*
*
* @author huangchengxing
*/
public interface AnnotationSynthesizer {
/**
*
*
* @return
*/
Object getSource();
/**
*
*
* @return
*/
SynthesizedAnnotationSelector getAnnotationSelector();
/**
*
*
* @return
*/
Collection<SynthesizedAnnotationPostProcessor> getAnnotationPostProcessors();
/**
*
*
* @param annotationType
* @return
*/
SynthesizedAnnotation getSynthesizedAnnotation(Class<?> annotationType);
/**
*
*
* @return
*/
Map<Class<? extends Annotation>, SynthesizedAnnotation> getAllSynthesizedAnnotation();
/**
*
*
* @param annotationType
* @param <T>
* @return
*/
<T extends Annotation> T synthesize(Class<T> annotationType);
}

View File

@ -0,0 +1,576 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.annotation.scanner.AnnotationScanner;
import aiyh.utils.tool.cn.hutool.core.annotation.scanner.MetaAnnotationScanner;
import aiyh.utils.tool.cn.hutool.core.annotation.scanner.MethodAnnotationScanner;
import aiyh.utils.tool.cn.hutool.core.annotation.scanner.TypeAnnotationScanner;
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
import aiyh.utils.tool.cn.hutool.core.exceptions.UtilException;
import aiyh.utils.tool.cn.hutool.core.lang.Opt;
import aiyh.utils.tool.cn.hutool.core.lang.func.Func1;
import aiyh.utils.tool.cn.hutool.core.lang.func.LambdaUtil;
import aiyh.utils.tool.cn.hutool.core.util.*;
import java.lang.annotation.*;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* <br>
*
*
* @author looly
* @since 4.0.9
*/
public class AnnotationUtil {
/**
*
*/
static final Set<Class<? extends Annotation>> META_ANNOTATIONS = CollUtil.newHashSet(Target.class, //
Retention.class, //
Inherited.class, //
Documented.class, //
SuppressWarnings.class, //
Override.class, //
Deprecated.class//
);
/**
* Jdk<br>
*
* <ul>
* <li>{@link Target}</li>
* <li>{@link Retention}</li>
* <li>{@link Inherited}</li>
* <li>{@link Documented}</li>
* <li>{@link SuppressWarnings}</li>
* <li>{@link Override}</li>
* <li>{@link Deprecated}</li>
* </ul>
*
* @param annotationType
* @return Jdk
*/
public static boolean isJdkMetaAnnotation(Class<? extends Annotation> annotationType) {
return META_ANNOTATIONS.contains(annotationType);
}
/**
* Jdk<br>
*
* <ul>
* <li>{@link Target}</li>
* <li>{@link Retention}</li>
* <li>{@link Inherited}</li>
* <li>{@link Documented}</li>
* <li>{@link SuppressWarnings}</li>
* <li>{@link Override}</li>
* <li>{@link Deprecated}</li>
* </ul>
*
* @param annotationType
* @return Jdk
*/
public static boolean isNotJdkMateAnnotation(Class<? extends Annotation> annotationType) {
return false == isJdkMetaAnnotation(annotationType);
}
/**
*
*
* @param annotationEle
* @return
*/
public static CombinationAnnotationElement toCombination(AnnotatedElement annotationEle) {
if (annotationEle instanceof CombinationAnnotationElement) {
return (CombinationAnnotationElement) annotationEle;
}
return new CombinationAnnotationElement(annotationEle);
}
/**
*
*
* @param annotationEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param isToCombination
* @return
*/
public static Annotation[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination) {
return getAnnotations(annotationEle, isToCombination, (Predicate<Annotation>) null);
}
/**
*
*
* @param <T>
* @param annotationEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param annotationType
* @return
* @since 5.8.0
*/
public static <T> T[] getCombinationAnnotations(AnnotatedElement annotationEle, Class<T> annotationType) {
return getAnnotations(annotationEle, true, annotationType);
}
/**
*
*
* @param <T>
* @param annotationEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param isToCombination
* @param annotationType
* @return
* @since 5.8.0
*/
public static <T> T[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination, Class<T> annotationType) {
final Annotation[] annotations = getAnnotations(annotationEle, isToCombination,
(annotation -> null == annotationType || annotationType.isAssignableFrom(annotation.getClass())));
final T[] result = ArrayUtil.newArray(annotationType, annotations.length);
for (int i = 0; i < annotations.length; i++) {
//noinspection unchecked
result[i] = (T) annotations[i];
}
return result;
}
/**
*
*
* @param annotationEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param isToCombination
* @param predicate {@link Predicate#test(Object)}{@code true}
* @return {@link AnnotatedElement}{@code null}{@code null}
* @since 5.8.0
*/
public static Annotation[] getAnnotations(AnnotatedElement annotationEle, boolean isToCombination, Predicate<Annotation> predicate) {
if (null == annotationEle) {
return null;
}
if (isToCombination) {
if (null == predicate) {
return toCombination(annotationEle).getAnnotations();
}
return CombinationAnnotationElement.of(annotationEle, predicate).getAnnotations();
}
final Annotation[] result = annotationEle.getAnnotations();
if (null == predicate) {
return result;
}
return ArrayUtil.filter(result, predicate::test);
}
/**
*
*
* @param <A>
* @param annotationEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param annotationType
* @return
*/
public static <A extends Annotation> A getAnnotation(AnnotatedElement annotationEle, Class<A> annotationType) {
return (null == annotationEle) ? null : toCombination(annotationEle).getAnnotation(annotationType);
}
/**
*
*
* @param annotationEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param annotationType
* @return
* @since 5.4.2
*/
public static boolean hasAnnotation(AnnotatedElement annotationEle, Class<? extends Annotation> annotationType) {
return null != getAnnotation(annotationEle, annotationType);
}
/**
* <br>
* null
*
* @param <T>
* @param annotationEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param annotationType
* @return
* @throws UtilException
*/
public static <T> T getAnnotationValue(AnnotatedElement annotationEle, Class<? extends Annotation> annotationType) throws UtilException {
return getAnnotationValue(annotationEle, annotationType, "value");
}
/**
* <br>
* null
*
* @param <T>
* @param annotationEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param annotationType
* @param propertyName name() name
* @return
* @throws UtilException
*/
public static <T> T getAnnotationValue(AnnotatedElement annotationEle, Class<? extends Annotation> annotationType, String propertyName) throws UtilException {
final Annotation annotation = getAnnotation(annotationEle, annotationType);
if (null == annotation) {
return null;
}
final Method method = ReflectUtil.getMethodOfObj(annotation, propertyName);
if (null == method) {
return null;
}
return ReflectUtil.invoke(annotation, method);
}
/**
* <br>
* null
*
* @param <A>
* @param <R>
* @param annotationEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param propertyName name() name
* @return
* @throws UtilException
* @since 5.8.9
*/
public static <A extends Annotation, R> R getAnnotationValue(AnnotatedElement annotationEle, Func1<A, R> propertyName) {
if (propertyName == null) {
return null;
} else {
final SerializedLambda lambda = LambdaUtil.resolve(propertyName);
final String instantiatedMethodType = lambda.getInstantiatedMethodType();
final Class<A> annotationClass = ClassUtil.loadClass(StrUtil.sub(instantiatedMethodType, 2, StrUtil.indexOf(instantiatedMethodType, ';')));
return getAnnotationValue(annotationEle, annotationClass, lambda.getImplMethodName());
}
}
/**
* <br>
* null
*
* @param annotationEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param annotationType
* @return
* @throws UtilException
*/
public static Map<String, Object> getAnnotationValueMap(AnnotatedElement annotationEle, Class<? extends Annotation> annotationType) throws UtilException {
final Annotation annotation = getAnnotation(annotationEle, annotationType);
if (null == annotation) {
return null;
}
final Method[] methods = ReflectUtil.getMethods(annotationType, t -> {
if (ArrayUtil.isEmpty(t.getParameterTypes())) {
// 只读取无参方法
final String name = t.getName();
// 跳过自有的几个方法
return (false == "hashCode".equals(name)) //
&& (false == "toString".equals(name)) //
&& (false == "annotationType".equals(name));
}
return false;
});
final HashMap<String, Object> result = new HashMap<>(methods.length, 1);
for (Method method : methods) {
result.put(method.getName(), ReflectUtil.invoke(annotation, method));
}
return result;
}
/**
* SOURCECLASSRUNTIME CLASS
*
* @param annotationType
* @return
*/
public static RetentionPolicy getRetentionPolicy(Class<? extends Annotation> annotationType) {
final Retention retention = annotationType.getAnnotation(Retention.class);
if (null == retention) {
return RetentionPolicy.CLASS;
}
return retention.value();
}
/**
* TYPE, METHOD, CONSTRUCTOR, FIELD, PARAMETER
*
* @param annotationType
* @return
*/
public static ElementType[] getTargetType(Class<? extends Annotation> annotationType) {
final Target target = annotationType.getAnnotation(Target.class);
if (null == target) {
return new ElementType[]{ElementType.TYPE, //
ElementType.FIELD, //
ElementType.METHOD, //
ElementType.PARAMETER, //
ElementType.CONSTRUCTOR, //
ElementType.LOCAL_VARIABLE, //
ElementType.ANNOTATION_TYPE, //
ElementType.PACKAGE//
};
}
return target.value();
}
/**
* Javadoc
*
* @param annotationType
* @return Javadoc
*/
public static boolean isDocumented(Class<? extends Annotation> annotationType) {
return annotationType.isAnnotationPresent(Documented.class);
}
/**
* false
*
* @param annotationType
* @return Javadoc
*/
public static boolean isInherited(Class<? extends Annotation> annotationType) {
return annotationType.isAnnotationPresent(Inherited.class);
}
/**
* {@link Class}{@link #META_ANNOTATIONS}JDK
* {@code annotationType}{@link Class#getAnnotations()}
*
* <p><br>
* {@code annotationType} AABBCD
* <pre>
* |-&gt; C.class [@a, @b]
* A.class -&gt; B.class [@a] -|
* |-&gt; D.class [@a, @c]
* </pre>
* A {@code [@a, @a, @b, @a, @c]}
*
* @param annotationType
* @return
* @see MetaAnnotationScanner
*/
public static List<Annotation> scanMetaAnnotation(Class<? extends Annotation> annotationType) {
return AnnotationScanner.DIRECTLY_AND_META_ANNOTATION.getAnnotationsIfSupport(annotationType);
}
/**
* <p>{@link Class}{@link #META_ANNOTATIONS}JDK,
* /{@link Class#getAnnotations()}<br>
* 广
* <ul>
* <li></li>
* <li>{@code targetClass}</li>
* <li>/</li>
* </ul>
* /{@link Class}{@link Class#getAnnotations()}
*
* <p><br>
* {@code targetClass}{@code A.class}{@code A.class}{@code B.class}{@code C.class}
*
* <pre>
* |-&gt; B.class [@a, @b]
* A.class [@a] -|
* |-&gt; C.class [@a, @c]
* </pre>
* {@code [@a, @a, @b, @a, @c]}
*
* @param targetClass
* @return
* @see TypeAnnotationScanner
*/
public static List<Annotation> scanClass(Class<?> targetClass) {
return AnnotationScanner.TYPE_HIERARCHY.getAnnotationsIfSupport(targetClass);
}
/**
* <p>{@link Class}
* {@link #META_ANNOTATIONS}JDK,
* {@link Method#getAnnotations()}<br>
* 广
* <ul>
* <li></li>
* <li>{@code targetClass}</li>
* <li>/</li>
* </ul>
* /{@link Method#getAnnotations()}
*
* <p><br>
* X{@code A.class}/{@code B.class}X{@code C.class}
*
* <pre>
* A#X()[@a] -&gt; B#X()[@b] -&gt; C#X()[@c]
* </pre>
* {@code [@a, @b, @c]}
*
* @param method
* @return
* @see MethodAnnotationScanner
*/
public static List<Annotation> scanMethod(Method method) {
return AnnotationScanner.TYPE_HIERARCHY.getAnnotationsIfSupport(method);
}
/**
*
*
* @param annotation
* @param annotationField
* @param value
* @since 5.5.2
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static void setValue(Annotation annotation, String annotationField, Object value) {
final Map memberValues = (Map) ReflectUtil.getFieldValue(Proxy.getInvocationHandler(annotation), "memberValues");
memberValues.put(annotationField, value);
}
/**
*
*
* @param annotation
* @return
* @see SynthesizedAnnotationProxy#isProxyAnnotation(Class)
*/
public static boolean isSynthesizedAnnotation(Annotation annotation) {
return SynthesizedAnnotationProxy.isProxyAnnotation(annotation.getClass());
}
/**
*
*
* @param annotationEle
* @param annotationType Class
* @param <T>
* @return
* @since 5.7.23
*/
public static <T extends Annotation> T getAnnotationAlias(AnnotatedElement annotationEle, Class<T> annotationType) {
final T annotation = getAnnotation(annotationEle, annotationType);
return aggregatingFromAnnotation(annotation).synthesize(annotationType);
}
/**
*
*
* @param annotationType
* @param annotations
* @param <T>
* @return
* @see SynthesizedAggregateAnnotation
*/
public static <T extends Annotation> T getSynthesizedAnnotation(Class<T> annotationType, Annotation... annotations) {
// TODO 缓存合成注解信息,避免重复解析
return Opt.ofNullable(annotations)
.filter(ArrayUtil::isNotEmpty)
.map(AnnotationUtil::aggregatingFromAnnotationWithMeta)
.map(a -> a.synthesize(annotationType))
.get();
}
/**
* <p>
* <ul>
* <li>;</li>
* <li>;</li>
* </ul>
*
* <p>
* {@code AnnotatedEle}ABC
* <pre>
* A -&gt; M3
* B -&gt; M1 -&gt; M2 -&gt; M3
* C -&gt; M2 -&gt; M3
* </pre>
* {@code annotationType}{@code M2}B
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param annotationType
* @param <T>
* @return
* @see SynthesizedAggregateAnnotation
*/
public static <T extends Annotation> T getSynthesizedAnnotation(AnnotatedElement annotatedEle, Class<T> annotationType) {
T target = annotatedEle.getAnnotation(annotationType);
if (ObjectUtil.isNotNull(target)) {
return target;
}
return AnnotationScanner.DIRECTLY
.getAnnotationsIfSupport(annotatedEle).stream()
.map(annotation -> getSynthesizedAnnotation(annotationType, annotation))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
/**
*
* <ul>
* <li>;</li>
* <li>;</li>
* </ul>
*
* <p>
* {@code AnnotatedEle}ABC
* <pre>
* A -&gt; M1 -&gt; M2
* B -&gt; M3 -&gt; M1 -&gt; M2
* C -&gt; M2
* </pre>
* {@code annotationType}{@code M1}AB
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param annotationType
* @param <T>
* @return
* @see SynthesizedAggregateAnnotation
*/
public static <T extends Annotation> List<T> getAllSynthesizedAnnotations(AnnotatedElement annotatedEle, Class<T> annotationType) {
return AnnotationScanner.DIRECTLY
.getAnnotationsIfSupport(annotatedEle).stream()
.map(annotation -> getSynthesizedAnnotation(annotationType, annotation))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
/**
*
*
* @param annotations
* @return
*/
public static SynthesizedAggregateAnnotation aggregatingFromAnnotation(Annotation... annotations) {
return new GenericSynthesizedAggregateAnnotation(Arrays.asList(annotations), AnnotationScanner.NOTHING);
}
/**
*
*
* @param annotations
* @return
*/
public static SynthesizedAggregateAnnotation aggregatingFromAnnotationWithMeta(Annotation... annotations) {
return new GenericSynthesizedAggregateAnnotation(Arrays.asList(annotations), AnnotationScanner.DIRECTLY_AND_META_ANNOTATION);
}
/**
* <br>
*
*
* @param method
*/
static boolean isAttributeMethod(Method method) {
return method.getParameterCount() == 0 && method.getReturnType() != void.class;
}
}

View File

@ -0,0 +1,63 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import aiyh.utils.tool.cn.hutool.core.util.ReflectUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
* {@link AnnotationAttribute}
*
* @author huangchengxing
*/
public class CacheableAnnotationAttribute implements AnnotationAttribute {
private boolean valueInvoked;
private Object value;
private boolean defaultValueInvoked;
private Object defaultValue;
private final Annotation annotation;
private final Method attribute;
public CacheableAnnotationAttribute(Annotation annotation, Method attribute) {
Assert.notNull(annotation, "annotation must not null");
Assert.notNull(attribute, "attribute must not null");
this.annotation = annotation;
this.attribute = attribute;
this.valueInvoked = false;
this.defaultValueInvoked = false;
}
@Override
public Annotation getAnnotation() {
return this.annotation;
}
@Override
public Method getAttribute() {
return this.attribute;
}
@Override
public Object getValue() {
if (!valueInvoked) {
valueInvoked = true;
value = ReflectUtil.invoke(annotation, attribute);
}
return value;
}
@Override
public boolean isValueEquivalentToDefaultValue() {
if (!defaultValueInvoked) {
defaultValue = attribute.getDefaultValue();
defaultValueInvoked = true;
}
return ObjectUtil.equals(getValue(), defaultValue);
}
}

View File

@ -0,0 +1,62 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.map.multi.RowKeyTable;
import aiyh.utils.tool.cn.hutool.core.map.multi.Table;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.util.Collection;
import java.util.Comparator;
/**
* <p>{@link SynthesizedAnnotationAttributeProcessor}
*
*
*
* <p>
*
* {@link Alias}{@link Link}
*
* @author huangchengxing
*/
public class CacheableSynthesizedAnnotationAttributeProcessor implements SynthesizedAnnotationAttributeProcessor {
private final Table<String, Class<?>, Object> valueCaches = new RowKeyTable<>();
private final Comparator<Hierarchical> annotationComparator;
/**
*
*
* @param annotationComparator
*/
public CacheableSynthesizedAnnotationAttributeProcessor(Comparator<Hierarchical> annotationComparator) {
Assert.notNull(annotationComparator, "annotationComparator must not null");
this.annotationComparator = annotationComparator;
}
/**
*
* {@link SynthesizedAnnotation#getVerticalDistance()}{@link SynthesizedAnnotation#getHorizontalDistance()}
*
*/
public CacheableSynthesizedAnnotationAttributeProcessor() {
this(Hierarchical.DEFAULT_HIERARCHICAL_COMPARATOR);
}
@SuppressWarnings("unchecked")
@Override
public <T> T getAttributeValue(String attributeName, Class<T> attributeType, Collection<? extends SynthesizedAnnotation> synthesizedAnnotations) {
Object value = valueCaches.get(attributeName, attributeType);
// 此处理论上不可能出现缓存值为nul的情况
if (ObjectUtil.isNotNull(value)) {
return (T)value;
}
value = synthesizedAnnotations.stream()
.filter(ma -> ma.hasAttribute(attributeName, attributeType))
.min(annotationComparator)
.map(ma -> ma.getAttributeValue(attributeName))
.orElse(null);
valueCaches.put(attributeName, attributeType, value);
return (T)value;
}
}

View File

@ -0,0 +1,165 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.map.TableMap;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.function.Predicate;
/**
* JDKSpring<br>
* 使
*
* @author Succy, Looly
* @since 4.0.9
**/
public class CombinationAnnotationElement implements AnnotatedElement, Serializable {
private static final long serialVersionUID = 1L;
/**
* CombinationAnnotationElement
*
* @param element ClassMethodFieldConstructorReflectPermission
* @param predicate {@link Predicate#test(Object)}{@code true}
* @return CombinationAnnotationElement
* @since 5.8.0
*/
public static CombinationAnnotationElement of(AnnotatedElement element, Predicate<Annotation> predicate) {
return new CombinationAnnotationElement(element, predicate);
}
/**
*
*/
private Map<Class<? extends Annotation>, Annotation> annotationMap;
/**
*
*/
private Map<Class<? extends Annotation>, Annotation> declaredAnnotationMap;
/**
*
*/
private final Predicate<Annotation> predicate;
/**
*
*
* @param element ClassMethodFieldConstructorReflectPermission
*/
public CombinationAnnotationElement(AnnotatedElement element) {
this(element, null);
}
/**
*
*
* @param element ClassMethodFieldConstructorReflectPermission
* @param predicate {@link Predicate#test(Object)}{@code true}
* @since 5.8.0
*/
public CombinationAnnotationElement(AnnotatedElement element, Predicate<Annotation> predicate) {
this.predicate = predicate;
init(element);
}
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
return annotationMap.containsKey(annotationClass);
}
@Override
@SuppressWarnings("unchecked")
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
Annotation annotation = annotationMap.get(annotationClass);
return (annotation == null) ? null : (T) annotation;
}
@Override
public Annotation[] getAnnotations() {
final Collection<Annotation> annotations = this.annotationMap.values();
return annotations.toArray(new Annotation[0]);
}
@Override
public Annotation[] getDeclaredAnnotations() {
final Collection<Annotation> annotations = this.declaredAnnotationMap.values();
return annotations.toArray(new Annotation[0]);
}
/**
*
*
* @param element
*/
private void init(AnnotatedElement element) {
final Annotation[] declaredAnnotations = element.getDeclaredAnnotations();
this.declaredAnnotationMap = new TableMap<>();
parseDeclared(declaredAnnotations);
final Annotation[] annotations = element.getAnnotations();
if (Arrays.equals(declaredAnnotations, annotations)) {
this.annotationMap = this.declaredAnnotationMap;
} else {
this.annotationMap = new TableMap<>();
parse(annotations);
}
}
/**
*
*
* @param annotations Class, Method, Field
*/
private void parseDeclared(Annotation[] annotations) {
Class<? extends Annotation> annotationType;
// 直接注解
for (Annotation annotation : annotations) {
annotationType = annotation.annotationType();
// issue#I5FQGW@Gitee跳过元注解和已经处理过的注解防止递归调用
if (AnnotationUtil.isNotJdkMateAnnotation(annotationType)
&& false == declaredAnnotationMap.containsKey(annotationType)) {
if(test(annotation)){
declaredAnnotationMap.put(annotationType, annotation);
}
// 测试不通过的注解,不影响继续递归
parseDeclared(annotationType.getDeclaredAnnotations());
}
}
}
/**
*
*
* @param annotations Class, Method, Field
*/
private void parse(Annotation[] annotations) {
Class<? extends Annotation> annotationType;
for (Annotation annotation : annotations) {
annotationType = annotation.annotationType();
// issue#I5FQGW@Gitee跳过元注解和已经处理过的注解防止递归调用
if (AnnotationUtil.isNotJdkMateAnnotation(annotationType)
&& false == declaredAnnotationMap.containsKey(annotationType)) {
if(test(annotation)){
annotationMap.put(annotationType, annotation);
}
// 测试不通过的注解,不影响继续递归
parse(annotationType.getAnnotations());
}
}
}
/**
*
*
* @param annotation
* @return
*/
private boolean test(Annotation annotation) {
return null == this.predicate || this.predicate.test(annotation);
}
}

View File

@ -0,0 +1,35 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import java.lang.annotation.*;
/**
* <p>{@link Link}{@link Alias}
*
* <b>{@link Link}{@link AliasFor}{@link MirrorFor}使</b>
*
* @author huangchengxing
* @see Link
* @see RelationType#FORCE_ALIAS_FOR
*/
@Link(type = RelationType.FORCE_ALIAS_FOR)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface ForceAliasFor {
/**
*
*
* @return
*/
@Link(annotation = Link.class, attribute = "annotation", type = RelationType.FORCE_ALIAS_FOR)
Class<? extends Annotation> annotation() default Annotation.class;
/**
* {@link #annotation()}
*
* @return
*/
@Link(annotation = Link.class, attribute = "attribute", type = RelationType.FORCE_ALIAS_FOR)
String attribute() default "";
}

View File

@ -0,0 +1,49 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
/**
*
* {@link #getValue()}{@link #linked}
*
* @author huangchengxing
* @see AliasAnnotationPostProcessor
* @see AliasLinkAnnotationPostProcessor
* @see RelationType#ALIAS_FOR
* @see RelationType#FORCE_ALIAS_FOR
*/
public class ForceAliasedAnnotationAttribute extends AbstractWrappedAnnotationAttribute {
protected ForceAliasedAnnotationAttribute(AnnotationAttribute origin, AnnotationAttribute linked) {
super(origin, linked);
}
/**
* {@link #linked}{@link AnnotationAttribute#getValue()}
*
* @return {@link #linked}{@link AnnotationAttribute#getValue()}
*/
@Override
public Object getValue() {
return linked.getValue();
}
/**
* {@link #linked}{@link AnnotationAttribute#isValueEquivalentToDefaultValue()}
*
* @return {@link #linked}{@link AnnotationAttribute#isValueEquivalentToDefaultValue()}
*/
@Override
public boolean isValueEquivalentToDefaultValue() {
return linked.isValueEquivalentToDefaultValue();
}
/**
* {@link #linked}{@link AnnotationAttribute#getAttributeType()}
*
* @return {@link #linked}{@link AnnotationAttribute#getAttributeType()}
*/
@Override
public Class<?> getAttributeType() {
return linked.getAttributeType();
}
}

View File

@ -0,0 +1,318 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.annotation.scanner.AnnotationScanner;
import aiyh.utils.tool.cn.hutool.core.annotation.scanner.MetaAnnotationScanner;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.lang.Opt;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.*;
/**
* {@link SynthesizedAggregateAnnotation}
*
*
* <p>A{@link #annotationScanner}A
* ABBCAABC{@link GenericSynthesizedAggregateAnnotation}
* {@link AnnotatedElement}ABC
* {@link AnnotatedElement}
*
* <p>
* {@link SynthesizedAnnotationSelector}
* <br>
* 使{@link SynthesizedAnnotationSelector#NEAREST_AND_OLDEST_PRIORITY}
*
*
* <p>{@link SynthesizedAnnotationSelector}
* {@link MetaAnnotation}使{@link AliasAnnotationPostProcessor}
* <br>
* {@link Alias}{@link Link}
* <ul>
* <li>{@link AliasAnnotationPostProcessor}</li>
* <li>{@link MirrorLinkAnnotationPostProcessor}</li>
* <li>{@link AliasLinkAnnotationPostProcessor}</li>
* </ul>
*
*
* <p>{@link GenericSynthesizedAggregateAnnotation}{@link #getAttributeValue(String, Class)}
* {@link #synthesize(Class)}
* {@link Alias}{@link Link}
* {@link SynthesizedAnnotationAttributeProcessor}<br>
* {@link CacheableSynthesizedAnnotationAttributeProcessor}
*
*
* @author huangchengxing
* @see AnnotationUtil
* @see SynthesizedAnnotationProxy
* @see SynthesizedAnnotationSelector
* @see SynthesizedAnnotationAttributeProcessor
* @see SynthesizedAnnotationPostProcessor
* @see AnnotationSynthesizer
* @see AnnotationScanner
*/
public class GenericSynthesizedAggregateAnnotation
extends AbstractAnnotationSynthesizer<List<Annotation>>
implements SynthesizedAggregateAnnotation {
/**
*
*/
private final Object root;
/**
*
*/
private final int verticalDistance;
/**
*
*/
private final int horizontalDistance;
/**
*
*/
private final SynthesizedAnnotationAttributeProcessor attributeProcessor;
/**
*
* ,
*
*
* @param source
*/
public GenericSynthesizedAggregateAnnotation(Annotation... source) {
this(Arrays.asList(source), new MetaAnnotationScanner());
}
/**
*
*
*
*
* @param source
* @param annotationScanner
*/
public GenericSynthesizedAggregateAnnotation(List<Annotation> source, AnnotationScanner annotationScanner) {
this(
source, SynthesizedAnnotationSelector.NEAREST_AND_OLDEST_PRIORITY,
new CacheableSynthesizedAnnotationAttributeProcessor(),
Arrays.asList(
SynthesizedAnnotationPostProcessor.ALIAS_ANNOTATION_POST_PROCESSOR,
SynthesizedAnnotationPostProcessor.MIRROR_LINK_ANNOTATION_POST_PROCESSOR,
SynthesizedAnnotationPostProcessor.ALIAS_LINK_ANNOTATION_POST_PROCESSOR
),
annotationScanner
);
}
/**
*
*
* @param source
* @param annotationSelector
* @param attributeProcessor
* @param annotationPostProcessors
* @param annotationScanner
*/
public GenericSynthesizedAggregateAnnotation(
List<Annotation> source,
SynthesizedAnnotationSelector annotationSelector,
SynthesizedAnnotationAttributeProcessor attributeProcessor,
Collection<SynthesizedAnnotationPostProcessor> annotationPostProcessors,
AnnotationScanner annotationScanner) {
this(
null, 0, 0,
source, annotationSelector, attributeProcessor, annotationPostProcessors, annotationScanner
);
}
/**
*
*
* @param root
* @param verticalDistance
* @param horizontalDistance
* @param source
* @param annotationSelector
* @param attributeProcessor
* @param annotationPostProcessors
* @param annotationScanner
*/
GenericSynthesizedAggregateAnnotation(
Object root, int verticalDistance, int horizontalDistance,
List<Annotation> source,
SynthesizedAnnotationSelector annotationSelector,
SynthesizedAnnotationAttributeProcessor attributeProcessor,
Collection<SynthesizedAnnotationPostProcessor> annotationPostProcessors,
AnnotationScanner annotationScanner) {
super(source, annotationSelector, annotationPostProcessors, annotationScanner);
Assert.notNull(attributeProcessor, "attributeProcessor must not null");
this.root = ObjectUtil.defaultIfNull(root, this);
this.verticalDistance = verticalDistance;
this.horizontalDistance = horizontalDistance;
this.attributeProcessor = attributeProcessor;
}
/**
*
*
* @return
*/
@Override
public Object getRoot() {
return root;
}
/**
*
*
* @return
*/
@Override
public int getVerticalDistance() {
return verticalDistance;
}
/**
*
*
* @return
*/
@Override
public int getHorizontalDistance() {
return horizontalDistance;
}
/**
* 广{@link #source}
*/
@Override
protected Map<Class<? extends Annotation>, SynthesizedAnnotation> loadAnnotations() {
Map<Class<? extends Annotation>, SynthesizedAnnotation> annotationMap = new LinkedHashMap<>();
// 根注解默认水平坐标为0根注解的元注解坐标从1开始
for (int i = 0; i < source.size(); i++) {
final Annotation sourceAnnotation = source.get(i);
Assert.isFalse(AnnotationUtil.isSynthesizedAnnotation(sourceAnnotation), "source [{}] has been synthesized");
annotationMap.put(sourceAnnotation.annotationType(), new MetaAnnotation(sourceAnnotation, sourceAnnotation, 0, i));
Assert.isTrue(
annotationScanner.support(sourceAnnotation.annotationType()),
"annotation scanner [{}] cannot support scan [{}]",
annotationScanner, sourceAnnotation.annotationType()
);
annotationScanner.scan(
(index, annotation) -> {
SynthesizedAnnotation oldAnnotation = annotationMap.get(annotation.annotationType());
SynthesizedAnnotation newAnnotation = new MetaAnnotation(sourceAnnotation, annotation, index + 1, annotationMap.size());
if (ObjectUtil.isNull(oldAnnotation)) {
annotationMap.put(annotation.annotationType(), newAnnotation);
} else {
annotationMap.put(annotation.annotationType(), annotationSelector.choose(oldAnnotation, newAnnotation));
}
},
sourceAnnotation.annotationType(), null
);
}
return annotationMap;
}
/**
*
*
* @return
*/
@Override
public SynthesizedAnnotationAttributeProcessor getAnnotationAttributeProcessor() {
return this.attributeProcessor;
}
/**
* {@link Alias}{@link Alias#value()}
* <p>
*
* @param attributeName
* @param attributeType
* @return
*/
@Override
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
return attributeProcessor.getAttributeValue(attributeName, attributeType, synthesizedAnnotationMap.values());
}
/**
*
*
* @param annotationType
* @param <T>
* @return
*/
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
return Opt.ofNullable(annotationType)
.map(synthesizedAnnotationMap::get)
.map(SynthesizedAnnotation::getAnnotation)
.map(annotationType::cast)
.orElse(null);
}
/**
*
*
* @param annotationType
* @return
*/
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
return synthesizedAnnotationMap.containsKey(annotationType);
}
/**
*
*
* @return
*/
@Override
public Annotation[] getAnnotations() {
return synthesizedAnnotationMap.values().stream()
.map(SynthesizedAnnotation::getAnnotation)
.toArray(Annotation[]::new);
}
/**
* 使
*
* @param annotationType
* @return
* @see SynthesizedAnnotationProxy#create(Class, AnnotationAttributeValueProvider, SynthesizedAnnotation)
*/
@Override
public <T extends Annotation> T synthesize(Class<T> annotationType, SynthesizedAnnotation annotation) {
return SynthesizedAnnotationProxy.create(annotationType, this, annotation);
}
/**
* {@link #source}{@link #source}
*
* @author huangchengxing
*/
public static class MetaAnnotation extends GenericSynthesizedAnnotation<Annotation, Annotation> {
/**
*
*
* @param root
* @param annotation
* @param verticalDistance
* @param horizontalDistance
*/
protected MetaAnnotation(Annotation root, Annotation annotation, int verticalDistance, int horizontalDistance) {
super(root, annotation, verticalDistance, horizontalDistance);
}
}
}

View File

@ -0,0 +1,197 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.lang.Opt;
import aiyh.utils.tool.cn.hutool.core.util.ClassUtil;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* {@link SynthesizedAnnotation}
*
* @param <R>
* @param <T>
* @author huangchengxing
*/
public class GenericSynthesizedAnnotation<R, T extends Annotation> implements SynthesizedAnnotation {
private final R root;
private final T annotation;
private final Map<String, AnnotationAttribute> attributeMethodCaches;
private final int verticalDistance;
private final int horizontalDistance;
/**
*
*
* @param root
* @param annotation
* @param verticalDistance
* @param horizontalDistance
*/
protected GenericSynthesizedAnnotation(
R root, T annotation, int verticalDistance, int horizontalDistance) {
this.root = root;
this.annotation = annotation;
this.verticalDistance = verticalDistance;
this.horizontalDistance = horizontalDistance;
this.attributeMethodCaches = new HashMap<>();
this.attributeMethodCaches.putAll(loadAttributeMethods());
}
/**
*
*
* @return
*/
protected Map<String, AnnotationAttribute> loadAttributeMethods() {
return Stream.of(ClassUtil.getDeclaredMethods(annotation.annotationType()))
.filter(AnnotationUtil::isAttributeMethod)
.collect(Collectors.toMap(Method::getName, method -> new CacheableAnnotationAttribute(annotation, method)));
}
/**
*
*
* @param attributeName
* @return
*/
public boolean hasAttribute(String attributeName) {
return attributeMethodCaches.containsKey(attributeName);
}
/**
*
*
* @param attributeName
* @param returnType
* @return
*/
@Override
public boolean hasAttribute(String attributeName, Class<?> returnType) {
return Opt.ofNullable(attributeMethodCaches.get(attributeName))
.filter(method -> ClassUtil.isAssignable(returnType, method.getAttributeType()))
.isPresent();
}
/**
*
*
* @return
*/
@Override
public Map<String, AnnotationAttribute> getAttributes() {
return this.attributeMethodCaches;
}
/**
*
*
* @param attributeName
* @param attribute
*/
@Override
public void setAttribute(String attributeName, AnnotationAttribute attribute) {
attributeMethodCaches.put(attributeName, attribute);
}
/**
*
*
* @param attributeName
* @param operator
*/
@Override
public void replaceAttribute(String attributeName, UnaryOperator<AnnotationAttribute> operator) {
AnnotationAttribute old = attributeMethodCaches.get(attributeName);
if (ObjectUtil.isNotNull(old)) {
attributeMethodCaches.put(attributeName, operator.apply(old));
}
}
/**
*
*
* @param attributeName
* @return
*/
@Override
public Object getAttributeValue(String attributeName) {
return Opt.ofNullable(attributeMethodCaches.get(attributeName))
.map(AnnotationAttribute::getValue)
.get();
}
/**
*
*
* @return
*/
@Override
public R getRoot() {
return root;
}
/**
*
*
* @return
*/
@Override
public T getAnnotation() {
return annotation;
}
/**
*
*
*
* @return
*/
@Override
public int getVerticalDistance() {
return verticalDistance;
}
/**
*
*
*
* @return
*/
@Override
public int getHorizontalDistance() {
return horizontalDistance;
}
/**
*
*
* @return
*/
@Override
public Class<? extends Annotation> annotationType() {
return annotation.annotationType();
}
/**
*
*
* @param attributeName
* @param attributeType
* @return
*/
@Override
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
return Opt.ofNullable(attributeMethodCaches.get(attributeName))
.filter(method -> ClassUtil.isAssignable(attributeType, method.getAttributeType()))
.map(AnnotationAttribute::getValue)
.get();
}
}

View File

@ -0,0 +1,155 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import java.util.Comparator;
/**
* <p>
*
* <p>{@link #getVerticalDistance()}{@link #getHorizontalDistance()}
* <br>
* {@link #getRoot()}
* {@link #DEFAULT_HIERARCHICAL_COMPARATOR}<br>
* {@link #getRoot()}
*
* <p>{@link Selector}{@link Hierarchical}
*
* <ul>
* <li>{@link Selector#NEAREST_AND_OLDEST_PRIORITY}: </li>
* <li>{@link Selector#NEAREST_AND_NEWEST_PRIORITY}: </li>
* <li>{@link Selector#FARTHEST_AND_OLDEST_PRIORITY}: </li>
* <li>{@link Selector#FARTHEST_AND_NEWEST_PRIORITY}: </li>
* </ul>
*
* @author huangchengxing
*/
public interface Hierarchical extends Comparable<Hierarchical> {
// ====================== compare ======================
/**
* {@link #getHorizontalDistance()}{@link #getVerticalDistance()}
*/
Comparator<Hierarchical> DEFAULT_HIERARCHICAL_COMPARATOR = Comparator
.comparing(Hierarchical::getVerticalDistance)
.thenComparing(Hierarchical::getHorizontalDistance);
/**
* {@link #getVerticalDistance()}{@link #getHorizontalDistance()}
*
* @param o {@link SynthesizedAnnotation}
* @return
*/
@Override
default int compareTo(Hierarchical o) {
return DEFAULT_HIERARCHICAL_COMPARATOR.compare(this, o);
}
// ====================== hierarchical ======================
/**
* {@code (0, 0)}
*
*
* @return
*/
Object getRoot();
/**
*
*
*
* @return
*/
int getVerticalDistance();
/**
*
* {@link #getVerticalDistance()}
*
*
* @return
*/
int getHorizontalDistance();
// ====================== selector ======================
/**
* {@link Hierarchical}{@link Hierarchical}
*/
@FunctionalInterface
interface Selector {
/**
*
*/
Selector NEAREST_AND_OLDEST_PRIORITY = new NearestAndOldestPrioritySelector();
/**
*
*/
Selector NEAREST_AND_NEWEST_PRIORITY = new NearestAndNewestPrioritySelector();
/**
*
*/
Selector FARTHEST_AND_OLDEST_PRIORITY = new FarthestAndOldestPrioritySelector();
/**
*
*/
Selector FARTHEST_AND_NEWEST_PRIORITY = new FarthestAndNewestPrioritySelector();
/**
*
*
* @param <T>
* @param prev
* @param next
* @return
*/
<T extends Hierarchical> T choose(T prev, T next);
/**
*
*/
class NearestAndOldestPrioritySelector implements Selector {
@Override
public <T extends Hierarchical> T choose(T oldAnnotation, T newAnnotation) {
return newAnnotation.getVerticalDistance() < oldAnnotation.getVerticalDistance() ? newAnnotation : oldAnnotation;
}
}
/**
*
*/
class NearestAndNewestPrioritySelector implements Selector {
@Override
public <T extends Hierarchical> T choose(T oldAnnotation, T newAnnotation) {
return newAnnotation.getVerticalDistance() <= oldAnnotation.getVerticalDistance() ? newAnnotation : oldAnnotation;
}
}
/**
*
*/
class FarthestAndOldestPrioritySelector implements Selector {
@Override
public <T extends Hierarchical> T choose(T oldAnnotation, T newAnnotation) {
return newAnnotation.getVerticalDistance() > oldAnnotation.getVerticalDistance() ? newAnnotation : oldAnnotation;
}
}
/**
*
*/
class FarthestAndNewestPrioritySelector implements Selector {
@Override
public <T extends Hierarchical> T choose(T oldAnnotation, T newAnnotation) {
return newAnnotation.getVerticalDistance() >= oldAnnotation.getVerticalDistance() ? newAnnotation : oldAnnotation;
}
}
}
}

View File

@ -0,0 +1,49 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import java.lang.annotation.*;
/**
* <p>
* {@link SynthesizedAggregateAnnotation}<br>
*
* <p>{@link MirrorFor}{@link ForceAliasFor}{@link AliasFor}
* 使{@link Link}
* {@link Link}{@link Link}
*
*
* <b>{@link Alias}</b>
*
* @author huangchengxing
* @see SynthesizedAggregateAnnotation
* @see RelationType
* @see AliasFor
* @see MirrorFor
* @see ForceAliasFor
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Link {
/**
*
*
* @return
*/
Class<? extends Annotation> annotation() default Annotation.class;
/**
* {@link #annotation()}
*
* @return
*/
String attribute() default "";
/**
* {@link #attribute()}
*
* @return
*/
RelationType type() default RelationType.MIRROR_FOR;
}

View File

@ -0,0 +1,42 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import java.lang.annotation.*;
/**
* <p>{@link Link}<br>
*
* <ul>
* <li>{@code MIRROR_FOR}{@link Link}</li>
* <li></li>
* <li></li>
* <li></li>
* </ul>
* <b>{@link Link}{@link ForceAliasFor}{@link AliasFor}使</b>
*
* @author huangchengxing
* @see Link
* @see RelationType#MIRROR_FOR
*/
@Link(type = RelationType.MIRROR_FOR)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface MirrorFor {
/**
*
*
* @return
*/
@Link(annotation = Link.class, attribute = "annotation", type = RelationType.FORCE_ALIAS_FOR)
Class<? extends Annotation> annotation() default Annotation.class;
/**
* {@link #annotation()}
*
* @return
*/
@Link(annotation = Link.class, attribute = "attribute", type = RelationType.FORCE_ALIAS_FOR)
String attribute() default "";
}

View File

@ -0,0 +1,132 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.text.CharSequenceUtil;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
/**
* <p>{@link Link}{@link Link#type()}{@link RelationType#MIRROR_FOR}<br>
* {@link Link}{@link Link}
* {@link MirroredAnnotationAttribute}
*
* @author huangchengxing
* @see RelationType#MIRROR_FOR
* @see MirroredAnnotationAttribute
*/
public class MirrorLinkAnnotationPostProcessor extends AbstractLinkAnnotationPostProcessor {
private static final RelationType[] PROCESSED_RELATION_TYPES = new RelationType[]{ RelationType.MIRROR_FOR };
@Override
public int order() {
return Integer.MIN_VALUE + 1;
}
/**
* {@link Link#type()}{@link RelationType#MIRROR_FOR}
*
* @return {@link RelationType#MIRROR_FOR}
*/
@Override
protected RelationType[] processTypes() {
return PROCESSED_RELATION_TYPES;
}
/**
* {@link MirroredAnnotationAttribute}
* 使{@link MirroredAnnotationAttribute}{@link AnnotationAttribute}
*
* @param synthesizer
* @param annotation {@code originalAttribute}{@link Link}
* @param originalAnnotation {@link SynthesizedAnnotation}
* @param originalAttribute {@code originalAnnotation}
* @param linkedAnnotation {@link Link}
* @param linkedAttribute {@link Link}{@code originalAnnotation}
*/
@Override
protected void processLinkedAttribute(
AnnotationSynthesizer synthesizer, Link annotation,
SynthesizedAnnotation originalAnnotation, AnnotationAttribute originalAttribute,
SynthesizedAnnotation linkedAnnotation, AnnotationAttribute linkedAttribute) {
// 镜像属性必然成对出现,因此此处必定存在三种情况:
// 1.两属性都不为镜像属性,此时继续进行后续处理;
// 2.两属性都为镜像属性,并且指向对方,此时无需后续处理;
// 3.两属性仅有任意一属性为镜像属性,此时镜像属性必然未指向当前原始属性,此时应该抛出异常;
if (originalAttribute instanceof MirroredAnnotationAttribute
|| linkedAttribute instanceof MirroredAnnotationAttribute) {
checkMirrored(originalAttribute, linkedAttribute);
return;
}
// 校验镜像关系
checkMirrorRelation(annotation, originalAttribute, linkedAttribute);
// 包装这一对镜像属性,并替换原注解中的对应属性
final AnnotationAttribute mirroredOriginalAttribute = new MirroredAnnotationAttribute(originalAttribute, linkedAttribute);
originalAnnotation.setAttribute(originalAttribute.getAttributeName(), mirroredOriginalAttribute);
final AnnotationAttribute mirroredTargetAttribute = new MirroredAnnotationAttribute(linkedAttribute, originalAttribute);
linkedAnnotation.setAttribute(annotation.attribute(), mirroredTargetAttribute);
}
/**
*
*/
private void checkMirrored(AnnotationAttribute original, AnnotationAttribute mirror) {
final boolean originalAttributeMirrored = original instanceof MirroredAnnotationAttribute;
final boolean mirrorAttributeMirrored = mirror instanceof MirroredAnnotationAttribute;
// 校验通过
final boolean passed = originalAttributeMirrored && mirrorAttributeMirrored
&& ObjectUtil.equals(((MirroredAnnotationAttribute)original).getLinked(), ((MirroredAnnotationAttribute)mirror).getOriginal());
if (passed) {
return;
}
// 校验失败,拼装异常信息用于抛出异常
String errorMsg;
// 原始字段已经跟其他字段形成镜像
if (originalAttributeMirrored && !mirrorAttributeMirrored) {
errorMsg = CharSequenceUtil.format(
"attribute [{}] cannot mirror for [{}], because it's already mirrored for [{}]",
original.getAttribute(), mirror.getAttribute(), ((MirroredAnnotationAttribute)original).getLinked()
);
}
// 镜像字段已经跟其他字段形成镜像
else if (!originalAttributeMirrored && mirrorAttributeMirrored) {
errorMsg = CharSequenceUtil.format(
"attribute [{}] cannot mirror for [{}], because it's already mirrored for [{}]",
mirror.getAttribute(), original.getAttribute(), ((MirroredAnnotationAttribute)mirror).getLinked()
);
}
// 两者都形成了镜像,但是都未指向对方,理论上不会存在该情况
else {
errorMsg = CharSequenceUtil.format(
"attribute [{}] cannot mirror for [{}], because [{}] already mirrored for [{}] and [{}] already mirrored for [{}]",
mirror.getAttribute(), original.getAttribute(),
mirror.getAttribute(), ((MirroredAnnotationAttribute)mirror).getLinked(),
original.getAttribute(), ((MirroredAnnotationAttribute)original).getLinked()
);
}
throw new IllegalArgumentException(errorMsg);
}
/**
*
*/
private void checkMirrorRelation(Link annotation, AnnotationAttribute original, AnnotationAttribute mirror) {
// 镜像属性必须存在
checkLinkedAttributeNotNull(original, mirror, annotation);
// 镜像属性返回值必须一致
checkAttributeType(original, mirror);
// 镜像属性上必须存在对应的注解
final Link mirrorAttributeAnnotation = getLinkAnnotation(mirror, RelationType.MIRROR_FOR);
Assert.isTrue(
ObjectUtil.isNotNull(mirrorAttributeAnnotation) && RelationType.MIRROR_FOR.equals(mirrorAttributeAnnotation.type()),
"mirror attribute [{}] of original attribute [{}] must marked by @Link, and also @LinkType.type() must is [{}]",
mirror.getAttribute(), original.getAttribute(), RelationType.MIRROR_FOR
);
checkLinkedSelf(original, mirror);
}
}

View File

@ -0,0 +1,48 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
/**
* {@link RelationType#MIRROR_FOR}
*
* @author huangchengxing
* @see MirrorLinkAnnotationPostProcessor
* @see RelationType#MIRROR_FOR
*/
public class MirroredAnnotationAttribute extends AbstractWrappedAnnotationAttribute {
public MirroredAnnotationAttribute(AnnotationAttribute origin, AnnotationAttribute linked) {
super(origin, linked);
}
@Override
public Object getValue() {
final boolean originIsDefault = original.isValueEquivalentToDefaultValue();
final boolean targetIsDefault = linked.isValueEquivalentToDefaultValue();
final Object originValue = original.getValue();
final Object targetValue = linked.getValue();
// 都为默认值,或都为非默认值时,两方法的返回值必须相等
if (originIsDefault == targetIsDefault) {
Assert.equals(
originValue, targetValue,
"the values of attributes [{}] and [{}] that mirror each other are different: [{}] <==> [{}]",
original.getAttribute(), linked.getAttribute(), originValue, targetValue
);
return originValue;
}
// 两者有一者不为默认值时,优先返回非默认值
return originIsDefault ? targetValue : originValue;
}
/**
* {@link #original}{@link #linked}{@code true}
*
* @return
*/
@Override
public boolean isValueEquivalentToDefaultValue() {
return original.isValueEquivalentToDefaultValue() && linked.isValueEquivalentToDefaultValue();
}
}

View File

@ -0,0 +1,21 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 使BeanBeanMap<br>
* setXXXgetXXX
*
* @author Looly
* @since 5.4.2
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface PropIgnore {
}

View File

@ -0,0 +1,50 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
/**
* <p> <br>
* {@link Link}{@link Link}
* {@link SynthesizedAggregateAnnotation}<br>
* {@link Link#type()}{@link SynthesizedAggregateAnnotation}
*
* <p>
* <ol>
* <li>{@link Alias}</li>
* <li>{@link Link}{@link Link#type()}{@link #MIRROR_FOR}</li>
* <li>{@link Link}{@link Link#type()}{@link #FORCE_ALIAS_FOR}</li>
* <li>{@link Link}{@link Link#type()}{@link #ALIAS_FOR}</li>
* </ol>
*
* @author huangchengxing
* @see SynthesizedAggregateAnnotation
* @see Link
*/
public enum RelationType {
/**
* <p><br>
*
* <ul>
* <li>{@code MIRROR_FOR}{@link Link}</li>
* <li></li>
* <li></li>
* <li></li>
* </ul>
*/
MIRROR_FOR,
/**
* <p>
* <ul>
* <li></li>
* <li></li>
* </ul>
*/
ALIAS_FOR,
/**
* <p>{@link Alias}
*
*/
FORCE_ALIAS_FOR;
}

View File

@ -0,0 +1,102 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import java.lang.annotation.Annotation;
/**
* <p>
*
*
* <p>
* 使{@link SynthesizedAnnotationSelector}
* {@link SynthesizedAnnotation}
* {@link SynthesizedAggregateAnnotation}<br>
* {@link SynthesizedAnnotationSelector}
*
*
* <p>
* {@link SynthesizedAnnotationPostProcessor}
*
* {@link Link}<br>
* {@link SynthesizedAnnotationPostProcessor}
*
*
* <p>{@link #synthesize(Class)}
*
* {@link SynthesizedAnnotationAttributeProcessor}
* <br>
* {@link SynthesizedAnnotationAttributeProcessor}
*
*
* @author huangchengxing
* @see AnnotationSynthesizer
* @see SynthesizedAnnotation
* @see SynthesizedAnnotationSelector
* @see SynthesizedAnnotationAttributeProcessor
* @see SynthesizedAnnotationPostProcessor
* @see GenericSynthesizedAggregateAnnotation
*/
public interface SynthesizedAggregateAnnotation extends AggregateAnnotation, Hierarchical, AnnotationSynthesizer, AnnotationAttributeValueProvider {
// ================== hierarchical ==================
/**
* {@link #getRoot()}
* 0
*
* @return {@link #getRoot()}
*/
@Override
default int getVerticalDistance() {
return 0;
}
/**
* {@link #getRoot()}
* 0
*
* @return {@link #getRoot()}
*/
@Override
default int getHorizontalDistance() {
return 0;
}
// ================== synthesize ==================
/**
*
*
* @param annotationType
* @param <T>
* @return
*/
<T extends Annotation> T getAnnotation(Class<T> annotationType);
/**
*
*
* @return
*/
SynthesizedAnnotationAttributeProcessor getAnnotationAttributeProcessor();
/**
*
*
* @return
*/
@Override
default Class<? extends Annotation> annotationType() {
return this.getClass();
}
/**
*
*
* @param attributeName
* @param attributeType
* @return
*/
@Override
Object getAttributeValue(String attributeName, Class<?> attributeType);
}

View File

@ -0,0 +1,96 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
import java.lang.annotation.Annotation;
import java.util.Map;
import java.util.function.UnaryOperator;
/**
* <p>{@link SynthesizedAggregateAnnotation}<br>
* 使{@link #DEFAULT_HIERARCHICAL_COMPARATOR}
* {@link #getVerticalDistance()}{@link #getHorizontalDistance()}
* 使
*
* @author huangchengxing
* @see SynthesizedAggregateAnnotation
*/
public interface SynthesizedAnnotation extends Annotation, Hierarchical, AnnotationAttributeValueProvider {
/**
*
*
* @return
*/
Annotation getAnnotation();
/**
*
*
*
* @return
*/
@Override
int getVerticalDistance();
/**
*
*
*
* @return
*/
@Override
int getHorizontalDistance();
/**
*
*
* @param attributeName
* @param returnType
* @return
*/
boolean hasAttribute(String attributeName, Class<?> returnType);
/**
*
*
* @return
*/
Map<String, AnnotationAttribute> getAttributes();
/**
*
*
* @param attributes
*/
default void setAttributes(Map<String, AnnotationAttribute> attributes) {
if (CollUtil.isNotEmpty(attributes)) {
attributes.forEach(this::setAttribute);
}
}
/**
*
*
* @param attributeName
* @param attribute
*/
void setAttribute(String attributeName, AnnotationAttribute attribute);
/**
*
*
* @param attributeName
* @param operator
*/
void replaceAttribute(String attributeName, UnaryOperator<AnnotationAttribute> operator);
/**
*
*
* @param attributeName
* @return
*/
Object getAttributeValue(String attributeName);
}

View File

@ -0,0 +1,24 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import java.util.Collection;
/**
* {@link SynthesizedAggregateAnnotation}
*
* @author huangchengxing
*/
@FunctionalInterface
public interface SynthesizedAnnotationAttributeProcessor {
/**
*
*
* @param attributeName
* @param attributeType
* @param synthesizedAnnotations
* @param <R>
* @return
*/
<R> R getAttributeValue(String attributeName, Class<R> attributeType, Collection<? extends SynthesizedAnnotation> synthesizedAnnotations);
}

View File

@ -0,0 +1,71 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.comparator.CompareUtil;
import java.util.Comparator;
/**
* <p>{@link SynthesizedAggregateAnnotation}
* {@link SynthesizedAnnotation}<br>
* {@link SynthesizedAnnotationPostProcessor}{@link #order()}
*
*
* <p>
* <ul>
* <li>{@link AliasAnnotationPostProcessor}</li>
* <li>{@link MirrorLinkAnnotationPostProcessor}</li>
* <li>{@link AliasLinkAnnotationPostProcessor}</li>
* <li></li>
* </ul>
*
* @author huangchengxing
* @see AliasAnnotationPostProcessor
* @see MirrorLinkAnnotationPostProcessor
* @see AliasLinkAnnotationPostProcessor
*/
public interface SynthesizedAnnotationPostProcessor extends Comparable<SynthesizedAnnotationPostProcessor> {
/**
* {@link Alias}
*/
AliasAnnotationPostProcessor ALIAS_ANNOTATION_POST_PROCESSOR = new AliasAnnotationPostProcessor();
/**
* {@link Link}
*/
MirrorLinkAnnotationPostProcessor MIRROR_LINK_ANNOTATION_POST_PROCESSOR = new MirrorLinkAnnotationPostProcessor();
/**
* {@link Link}
*/
AliasLinkAnnotationPostProcessor ALIAS_LINK_ANNOTATION_POST_PROCESSOR = new AliasLinkAnnotationPostProcessor();
/**
*
*
* @return
*/
default int order() {
return Integer.MAX_VALUE;
}
/**
* {@link #order()}
*
* @param o
* @return
*/
@Override
default int compareTo(SynthesizedAnnotationPostProcessor o) {
return CompareUtil.compare(this, o, Comparator.comparing(SynthesizedAnnotationPostProcessor::order));
}
/**
*
*
* @param synthesizedAnnotation
* @param synthesizer
*/
void process(SynthesizedAnnotation synthesizedAnnotation, AnnotationSynthesizer synthesizer);
}

View File

@ -0,0 +1,160 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.lang.Opt;
import aiyh.utils.tool.cn.hutool.core.text.CharSequenceUtil;
import aiyh.utils.tool.cn.hutool.core.util.ClassUtil;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import aiyh.utils.tool.cn.hutool.core.util.ReflectUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* {@link SynthesizedAnnotation}
*
* @author huangchengxing
* @see SynthesizedAnnotation
* @see AnnotationAttributeValueProvider
*/
public class SynthesizedAnnotationProxy implements InvocationHandler {
private final AnnotationAttributeValueProvider annotationAttributeValueProvider;
private final SynthesizedAnnotation annotation;
private final Map<String, BiFunction<Method, Object[], Object>> methods;
/**
* {@link SyntheticProxyAnnotation}
*
* @param <T>
* @param annotationType
* @param annotationAttributeValueProvider
* @param annotation
* @return
*/
@SuppressWarnings("unchecked")
public static <T extends Annotation> T create(
Class<T> annotationType,
AnnotationAttributeValueProvider annotationAttributeValueProvider,
SynthesizedAnnotation annotation) {
if (ObjectUtil.isNull(annotation)) {
return null;
}
final SynthesizedAnnotationProxy proxyHandler = new SynthesizedAnnotationProxy(annotationAttributeValueProvider, annotation);
if (ObjectUtil.isNull(annotation)) {
return null;
}
return (T) Proxy.newProxyInstance(
annotationType.getClassLoader(),
new Class[]{annotationType, SyntheticProxyAnnotation.class},
proxyHandler
);
}
/**
* {@link SyntheticProxyAnnotation}
*
* @param <T>
* @param annotationType
* @param annotation
* @return
*/
public static <T extends Annotation> T create(
Class<T> annotationType, SynthesizedAnnotation annotation) {
return create(annotationType, annotation, annotation);
}
/**
* {@code SynthesizedAnnotationProxy}
*
* @param annotationType
* @return
*/
public static boolean isProxyAnnotation(Class<?> annotationType) {
return ClassUtil.isAssignable(SyntheticProxyAnnotation.class, annotationType);
}
SynthesizedAnnotationProxy(AnnotationAttributeValueProvider annotationAttributeValueProvider, SynthesizedAnnotation annotation) {
Assert.notNull(annotationAttributeValueProvider, "annotationAttributeValueProvider must not null");
Assert.notNull(annotation, "annotation must not null");
this.annotationAttributeValueProvider = annotationAttributeValueProvider;
this.annotation = annotation;
this.methods = new HashMap<>(9);
loadMethods();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return Opt.ofNullable(methods.get(method.getName()))
.map(m -> m.apply(method, args))
.orElseGet(() -> ReflectUtil.invoke(this, method, args));
}
// ========================= 代理方法 =========================
void loadMethods() {
methods.put("toString", (method, args) -> proxyToString());
methods.put("hashCode", (method, args) -> proxyHashCode());
methods.put("getSynthesizedAnnotation", (method, args) -> proxyGetSynthesizedAnnotation());
methods.put("getRoot", (method, args) -> annotation.getRoot());
methods.put("getVerticalDistance", (method, args) -> annotation.getVerticalDistance());
methods.put("getHorizontalDistance", (method, args) -> annotation.getHorizontalDistance());
methods.put("hasAttribute", (method, args) -> annotation.hasAttribute((String) args[0], (Class<?>) args[1]));
methods.put("getAttributes", (method, args) -> annotation.getAttributes());
methods.put("setAttribute", (method, args) -> {
throw new UnsupportedOperationException("proxied annotation can not reset attributes");
});
methods.put("getAttributeValue", (method, args) -> annotation.getAttributeValue((String) args[0]));
methods.put("annotationType", (method, args) -> annotation.annotationType());
for (final Method declaredMethod : ClassUtil.getDeclaredMethods(annotation.getAnnotation().annotationType())) {
methods.put(declaredMethod.getName(), (method, args) -> proxyAttributeValue(method));
}
}
private String proxyToString() {
final String attributes = Stream.of(ClassUtil.getDeclaredMethods(annotation.getAnnotation().annotationType()))
.filter(AnnotationUtil::isAttributeMethod)
.map(method -> CharSequenceUtil.format(
"{}={}", method.getName(), proxyAttributeValue(method))
)
.collect(Collectors.joining(", "));
return CharSequenceUtil.format("@{}({})", annotation.annotationType().getName(), attributes);
}
private int proxyHashCode() {
return Objects.hash(annotationAttributeValueProvider, annotation);
}
private Object proxyGetSynthesizedAnnotation() {
return annotation;
}
private Object proxyAttributeValue(Method attributeMethod) {
return annotationAttributeValueProvider.getAttributeValue(attributeMethod.getName(), attributeMethod.getReturnType());
}
/**
*
*
* @author huangchengxing
*/
interface SyntheticProxyAnnotation extends SynthesizedAnnotation {
/**
*
*
* @return
*/
SynthesizedAnnotation getSynthesizedAnnotation();
}
}

View File

@ -0,0 +1,82 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
/**
* <br>
* {@link SynthesizedAggregateAnnotation}
*
* @author huangchengxing
*/
@FunctionalInterface
public interface SynthesizedAnnotationSelector {
/**
*
*/
SynthesizedAnnotationSelector NEAREST_AND_OLDEST_PRIORITY = new NearestAndOldestPrioritySelector();
/**
*
*/
SynthesizedAnnotationSelector NEAREST_AND_NEWEST_PRIORITY = new NearestAndNewestPrioritySelector();
/**
*
*/
SynthesizedAnnotationSelector FARTHEST_AND_OLDEST_PRIORITY = new FarthestAndOldestPrioritySelector();
/**
*
*/
SynthesizedAnnotationSelector FARTHEST_AND_NEWEST_PRIORITY = new FarthestAndNewestPrioritySelector();
/**
*
*
* @param <T>
* @param oldAnnotation
* @param newAnnotation
* @return
*/
<T extends SynthesizedAnnotation> T choose(T oldAnnotation, T newAnnotation);
/**
*
*/
class NearestAndOldestPrioritySelector implements SynthesizedAnnotationSelector {
@Override
public <T extends SynthesizedAnnotation> T choose(T oldAnnotation, T newAnnotation) {
return Hierarchical.Selector.NEAREST_AND_OLDEST_PRIORITY.choose(oldAnnotation, newAnnotation);
}
}
/**
*
*/
class NearestAndNewestPrioritySelector implements SynthesizedAnnotationSelector {
@Override
public <T extends SynthesizedAnnotation> T choose(T oldAnnotation, T newAnnotation) {
return Hierarchical.Selector.NEAREST_AND_NEWEST_PRIORITY.choose(oldAnnotation, newAnnotation);
}
}
/**
*
*/
class FarthestAndOldestPrioritySelector implements SynthesizedAnnotationSelector {
@Override
public <T extends SynthesizedAnnotation> T choose(T oldAnnotation, T newAnnotation) {
return Hierarchical.Selector.FARTHEST_AND_OLDEST_PRIORITY.choose(oldAnnotation, newAnnotation);
}
}
/**
*
*/
class FarthestAndNewestPrioritySelector implements SynthesizedAnnotationSelector {
@Override
public <T extends SynthesizedAnnotation> T choose(T oldAnnotation, T newAnnotation) {
return Hierarchical.Selector.FARTHEST_AND_NEWEST_PRIORITY.choose(oldAnnotation, newAnnotation);
}
}
}

View File

@ -0,0 +1,125 @@
package aiyh.utils.tool.cn.hutool.core.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
/**
* <p>{@link AnnotationAttribute}
*
* 使<br>
* {@link #getValue()}{@link #getOriginal()}
* {@link AnnotationAttribute}
*
* <p>
* abab{@link MirroredAnnotationAttribute}
* cacab{@link AliasedAnnotationAttribute}<br>
* ab{@link AliasedAnnotationAttribute}
* c{@link MirroredAnnotationAttribute}
*
* <p>{@link AnnotationAttribute}
*
*
*
* @author huangchengxing
* @see AnnotationAttribute
* @see ForceAliasedAnnotationAttribute
* @see AliasedAnnotationAttribute
* @see MirroredAnnotationAttribute
*/
public interface WrappedAnnotationAttribute extends AnnotationAttribute {
// =========================== 新增方法 ===========================
/**
* {@link AnnotationAttribute}{@link AnnotationAttribute}
*
* @return {@link AnnotationAttribute}
*/
AnnotationAttribute getOriginal();
/**
* {@link AnnotationAttribute}
*
* @return {@link AnnotationAttribute}
*/
AnnotationAttribute getNonWrappedOriginal();
/**
* {@link #getOriginal()}{@link AnnotationAttribute}{@link AnnotationAttribute}
*
* @return
*/
AnnotationAttribute getLinked();
/**
*
*
* @return
*/
Collection<AnnotationAttribute> getAllLinkedNonWrappedAttributes();
// =========================== 代理实现 ===========================
/**
*
*
* @return
*/
@Override
default Annotation getAnnotation() {
return getOriginal().getAnnotation();
}
/**
*
*
* @return
*/
@Override
default Method getAttribute() {
return getOriginal().getAttribute();
}
/**
* <br>
* {@link #getOriginal()}{@link #getLinked()}
* {@code true}
*
* @return
*/
@Override
boolean isValueEquivalentToDefaultValue();
/**
*
*
* @return
*/
@Override
default Class<?> getAttributeType() {
return getOriginal().getAttributeType();
}
/**
*
*
* @param annotationType
* @return
*/
@Override
default <T extends Annotation> T getAnnotation(Class<T> annotationType) {
return getOriginal().getAnnotation(annotationType);
}
/**
* {@link WrappedAnnotationAttribute}
*
* @return boolean
*/
@Override
default boolean isWrapped() {
return true;
}
}

View File

@ -0,0 +1,7 @@
/**
*
*
* @author looly
*
*/
package aiyh.utils.tool.cn.hutool.core.annotation;

View File

@ -0,0 +1,288 @@
package aiyh.utils.tool.cn.hutool.core.annotation.scanner;
import aiyh.utils.tool.cn.hutool.core.annotation.AnnotationUtil;
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.util.ArrayUtil;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
/**
* {@link AnnotationScanner}
*
* @author huangchengxing
*/
public abstract class AbstractTypeAnnotationScanner<T extends AbstractTypeAnnotationScanner<T>> implements AnnotationScanner {
/**
*
*/
private boolean includeSuperClass;
/**
*
*/
private boolean includeInterfaces;
/**
*
*/
private Predicate<Class<?>> filter;
/**
*
*/
private final Set<Class<?>> excludeTypes;
/**
*
*/
private final List<UnaryOperator<Class<?>>> converters;
/**
*
*/
private boolean hasConverters;
/**
*
*/
private final T typedThis;
/**
*
*
* @param includeSuperClass
* @param includeInterfaces
* @param filter
* @param excludeTypes
*/
@SuppressWarnings("unchecked")
protected AbstractTypeAnnotationScanner(boolean includeSuperClass, boolean includeInterfaces, Predicate<Class<?>> filter, Set<Class<?>> excludeTypes) {
Assert.notNull(filter, "filter must not null");
Assert.notNull(excludeTypes, "excludeTypes must not null");
this.includeSuperClass = includeSuperClass;
this.includeInterfaces = includeInterfaces;
this.filter = filter;
this.excludeTypes = excludeTypes;
this.converters = new ArrayList<>();
this.typedThis = (T) this;
}
/**
*
*
* @return
*/
public boolean isIncludeSuperClass() {
return includeSuperClass;
}
/**
*
*
* @return
*/
public boolean isIncludeInterfaces() {
return includeInterfaces;
}
/**
*
*
* @param filter
* @return
*/
public T setFilter(Predicate<Class<?>> filter) {
Assert.notNull(filter, "filter must not null");
this.filter = filter;
return typedThis;
}
/**
*
*
* @param excludeTypes
* @return
*/
public T addExcludeTypes(Class<?>... excludeTypes) {
CollUtil.addAll(this.excludeTypes, excludeTypes);
return typedThis;
}
/**
*
*
* @param converter
* @return
* @see JdkProxyClassConverter
*/
public T addConverters(UnaryOperator<Class<?>> converter) {
Assert.notNull(converter, "converter must not null");
this.converters.add(converter);
if (!this.hasConverters) {
this.hasConverters = CollUtil.isNotEmpty(this.converters);
}
return typedThis;
}
/**
*
*
* @param includeSuperClass
* @return
*/
protected T setIncludeSuperClass(boolean includeSuperClass) {
this.includeSuperClass = includeSuperClass;
return typedThis;
}
/**
*
*
* @param includeInterfaces
* @return
*/
protected T setIncludeInterfaces(boolean includeInterfaces) {
this.includeInterfaces = includeInterfaces;
return typedThis;
}
/**
* 广/
*
* @param consumer
* @param annotatedEle
* @param filter
*/
@Override
public void scan(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
filter = ObjectUtil.defaultIfNull(filter, a -> annotation -> true);
final Class<?> sourceClass = getClassFormAnnotatedElement(annotatedEle);
final Deque<List<Class<?>>> classDeque = CollUtil.newLinkedList(CollUtil.newArrayList(sourceClass));
final Set<Class<?>> accessedTypes = new LinkedHashSet<>();
int index = 0;
while (!classDeque.isEmpty()) {
final List<Class<?>> currClassQueue = classDeque.removeFirst();
final List<Class<?>> nextClassQueue = new ArrayList<>();
for (Class<?> targetClass : currClassQueue) {
targetClass = convert(targetClass);
// 过滤不需要处理的类
if (isNotNeedProcess(accessedTypes, targetClass)) {
continue;
}
accessedTypes.add(targetClass);
// 扫描父类
scanSuperClassIfNecessary(nextClassQueue, targetClass);
// 扫描接口
scanInterfaceIfNecessary(nextClassQueue, targetClass);
// 处理层级索引和注解
final Annotation[] targetAnnotations = getAnnotationsFromTargetClass(annotatedEle, index, targetClass);
for (final Annotation annotation : targetAnnotations) {
if (AnnotationUtil.isNotJdkMateAnnotation(annotation.annotationType()) && filter.test(annotation)) {
consumer.accept(index, annotation);
}
}
index++;
}
if (CollUtil.isNotEmpty(nextClassQueue)) {
classDeque.addLast(nextClassQueue);
}
}
}
/**
*
*
* @param annotatedElement
* @return
*/
protected abstract Class<?> getClassFormAnnotatedElement(AnnotatedElement annotatedElement);
/**
*
*
* @param source
* @param index
* @param targetClass
* @return
*/
protected abstract Annotation[] getAnnotationsFromTargetClass(AnnotatedElement source, int index, Class<?> targetClass);
/**
*
*
* @param accessedTypes 访
* @param targetClass
* @return
*/
protected boolean isNotNeedProcess(Set<Class<?>> accessedTypes, Class<?> targetClass) {
return ObjectUtil.isNull(targetClass)
|| accessedTypes.contains(targetClass)
|| excludeTypes.contains(targetClass)
|| filter.negate().test(targetClass);
}
/**
* {@link #includeInterfaces}{@code true}nextClasses
*
* @param nextClasses
* @param targetClass
*/
protected void scanInterfaceIfNecessary(List<Class<?>> nextClasses, Class<?> targetClass) {
if (includeInterfaces) {
final Class<?>[] interfaces = targetClass.getInterfaces();
if (ArrayUtil.isNotEmpty(interfaces)) {
CollUtil.addAll(nextClasses, interfaces);
}
}
}
/**
* {@link #includeSuperClass}{@code true}nextClasses
*
* @param nextClassQueue
* @param targetClass
*/
protected void scanSuperClassIfNecessary(List<Class<?>> nextClassQueue, Class<?> targetClass) {
if (includeSuperClass) {
final Class<?> superClass = targetClass.getSuperclass();
if (!ObjectUtil.equals(superClass, Object.class) && ObjectUtil.isNotNull(superClass)) {
nextClassQueue.add(superClass);
}
}
}
/**
* 使
*
* @param target
* @return
*/
protected Class<?> convert(Class<?> target) {
if (hasConverters) {
for (final UnaryOperator<Class<?>> converter : converters) {
target = converter.apply(target);
}
}
return target;
}
/**
* jdk
*/
public static class JdkProxyClassConverter implements UnaryOperator<Class<?>> {
@Override
public Class<?> apply(Class<?> sourceClass) {
return Proxy.isProxyClass(sourceClass) ? apply(sourceClass.getSuperclass()) : sourceClass;
}
}
}

View File

@ -0,0 +1,198 @@
package aiyh.utils.tool.cn.hutool.core.annotation.scanner;
import aiyh.utils.tool.cn.hutool.core.annotation.AnnotationUtil;
import aiyh.utils.tool.cn.hutool.core.util.ArrayUtil;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import java.lang.reflect.AnnotatedElement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* <p>
*
* <p>
* <ul>
* <li>{@link #NOTHING}</li>
* <li>{@link #DIRECTLY}{@link Inherited}</li>
* <li>
* {@link #DIRECTLY_AND_META_ANNOTATION}{@link Inherited}
*
* </li>
* <li>{@link #SUPERCLASS}</li>
* <li>{@link #SUPERCLASS_AND_META_ANNOTATION}</li>
* <li>{@link #INTERFACE}</li>
* <li>{@link #INTERFACE_AND_META_ANNOTATION}</li>
* <li>{@link #TYPE_HIERARCHY}</li>
* <li>{@link #TYPE_HIERARCHY_AND_META_ANNOTATION}</li>
* </ul>
*
* @author huangchengxing
* @see TypeAnnotationScanner
* @see MethodAnnotationScanner
* @see FieldAnnotationScanner
* @see MetaAnnotationScanner
* @see ElementAnnotationScanner
* @see GenericAnnotationScanner
*/
public interface AnnotationScanner {
// ============================ 预置的扫描器实例 ============================
/**
*
*/
AnnotationScanner NOTHING = new EmptyAnnotationScanner();
/**
* {@link Inherited}
*/
AnnotationScanner DIRECTLY = new GenericAnnotationScanner(false, false, false);
/**
* {@link Inherited}
*/
AnnotationScanner DIRECTLY_AND_META_ANNOTATION = new GenericAnnotationScanner(true, false, false);
/**
*
*/
AnnotationScanner SUPERCLASS = new GenericAnnotationScanner(false, true, false);
/**
*
*/
AnnotationScanner SUPERCLASS_AND_META_ANNOTATION = new GenericAnnotationScanner(true, true, false);
/**
*
*/
AnnotationScanner INTERFACE = new GenericAnnotationScanner(false, false, true);
/**
*
*/
AnnotationScanner INTERFACE_AND_META_ANNOTATION = new GenericAnnotationScanner(true, false, true);
/**
*
*/
AnnotationScanner TYPE_HIERARCHY = new GenericAnnotationScanner(false, true, true);
/**
*
*/
AnnotationScanner TYPE_HIERARCHY_AND_META_ANNOTATION = new GenericAnnotationScanner(true, true, true);
// ============================ 静态方法 ============================
/**
* 使
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param scanners
* @return
*/
static List<Annotation> scanByAnySupported(AnnotatedElement annotatedEle, AnnotationScanner... scanners) {
if (ObjectUtil.isNull(annotatedEle) && ArrayUtil.isNotEmpty(scanners)) {
return Collections.emptyList();
}
return Stream.of(scanners)
.filter(scanner -> scanner.support(annotatedEle))
.findFirst()
.map(scanner -> scanner.getAnnotations(annotatedEle))
.orElseGet(Collections::emptyList);
}
/**
*
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param scanners
* @return
*/
static List<Annotation> scanByAllSupported(AnnotatedElement annotatedEle, AnnotationScanner... scanners) {
if (ObjectUtil.isNull(annotatedEle) && ArrayUtil.isNotEmpty(scanners)) {
return Collections.emptyList();
}
return Stream.of(scanners)
.map(scanner -> scanner.getAnnotationsIfSupport(annotatedEle))
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
// ============================ 抽象方法 ============================
/**
*
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @return
*/
default boolean support(AnnotatedElement annotatedEle) {
return false;
}
/**
* {@link #support(AnnotatedElement)}true
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @return
*/
default List<Annotation> getAnnotations(AnnotatedElement annotatedEle) {
final List<Annotation> annotations = new ArrayList<>();
scan((index, annotation) -> annotations.add(annotation), annotatedEle, null);
return annotations;
}
/**
* {@link #support(AnnotatedElement)}{@code true}
* {@link #getAnnotations(AnnotatedElement)}
* {@link Collections#emptyList()}
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @return
*/
default List<Annotation> getAnnotationsIfSupport(AnnotatedElement annotatedEle) {
return support(annotatedEle) ? getAnnotations(annotatedEle) : Collections.emptyList();
}
/**
*
* {@link #support(AnnotatedElement)}true
*
* @param consumer
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param filter
*/
default void scan(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
filter = ObjectUtil.defaultIfNull(filter, (a)->annotation -> true);
for (final Annotation annotation : annotatedEle.getAnnotations()) {
if (AnnotationUtil.isNotJdkMateAnnotation(annotation.annotationType()) && filter.test(annotation)) {
consumer.accept(0, annotation);
}
}
}
/**
* {@link #support(AnnotatedElement)}{@code true}{@link #scan(BiConsumer, AnnotatedElement, Predicate)}
*
* @param consumer
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param filter
*/
default void scanIfSupport(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
if (support(annotatedEle)) {
scan(consumer, annotatedEle, filter);
}
}
}

View File

@ -0,0 +1,44 @@
package aiyh.utils.tool.cn.hutool.core.annotation.scanner;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* {@link AnnotatedElement}
*
* @author huangchengxing
*/
public class ElementAnnotationScanner implements AnnotationScanner {
/**
* {@code true}
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @return
*/
@Override
public boolean support(AnnotatedElement annotatedEle) {
return ObjectUtil.isNotNull(annotatedEle);
}
/**
* {@link AnnotatedElement}{@link #support(AnnotatedElement)}true
*
* @param consumer
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param filter
*/
@Override
public void scan(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
filter = ObjectUtil.defaultIfNull(filter,a-> t -> true);
Stream.of(annotatedEle.getAnnotations())
.filter(filter)
.forEach(annotation -> consumer.accept(0, annotation));
}
}

View File

@ -0,0 +1,31 @@
package aiyh.utils.tool.cn.hutool.core.annotation.scanner;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
/**
*
*
* @author huangchengxing
*/
public class EmptyAnnotationScanner implements AnnotationScanner {
@Override
public boolean support(AnnotatedElement annotatedEle) {
return true;
}
@Override
public List<Annotation> getAnnotations(AnnotatedElement annotatedEle) {
return Collections.emptyList();
}
@Override
public void scan(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
// do nothing
}
}

View File

@ -0,0 +1,47 @@
package aiyh.utils.tool.cn.hutool.core.annotation.scanner;
import aiyh.utils.tool.cn.hutool.core.annotation.AnnotationUtil;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
/**
* {@link Field}
*
* @author huangchengxing
*/
public class FieldAnnotationScanner implements AnnotationScanner {
/**
* {@link Field}{@code true}
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @return
*/
@Override
public boolean support(AnnotatedElement annotatedEle) {
return annotatedEle instanceof Field;
}
/**
* {@link Field}{@link #support(AnnotatedElement)}true
*
* @param consumer
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param filter
*/
@Override
public void scan(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
filter = ObjectUtil.defaultIfNull(filter, a -> annotation -> true);
for (final Annotation annotation : annotatedEle.getAnnotations()) {
if (AnnotationUtil.isNotJdkMateAnnotation(annotation.annotationType()) && filter.test(annotation)) {
consumer.accept(0, annotation);
}
}
}
}

View File

@ -0,0 +1,149 @@
package aiyh.utils.tool.cn.hutool.core.annotation.scanner;
import aiyh.utils.tool.cn.hutool.core.map.multi.ListValueMap;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
/**
* <p>{@link AnnotatedElement}
*
* <p>{@link AnnotatedElement}
* <ul>
* <li>
* {@link Method}
*
* </li>
* <li>
* {@link Class}
*
* </li>
* <li>{@link Method}{@link Class}</li>
* </ul>
*
*
* @author huangchengxing
* @see TypeAnnotationScanner
* @see MethodAnnotationScanner
* @see MetaAnnotationScanner
* @see ElementAnnotationScanner
*/
public class GenericAnnotationScanner implements AnnotationScanner {
/**
*
*/
private final AnnotationScanner typeScanner;
/**
*
*/
private final AnnotationScanner methodScanner;
/**
*
*/
private final AnnotationScanner metaScanner;
/**
*
*/
private final AnnotationScanner elementScanner;
/**
* {@link AnnotatedElement}
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @return
*/
@Override
public boolean support(AnnotatedElement annotatedEle) {
return true;
}
/**
*
*
* @param enableScanMetaAnnotation
* @param enableScanSupperClass
* @param enableScanSupperInterface
*/
public GenericAnnotationScanner(
boolean enableScanMetaAnnotation,
boolean enableScanSupperClass,
boolean enableScanSupperInterface) {
this.metaScanner = enableScanMetaAnnotation ? new MetaAnnotationScanner() : new EmptyAnnotationScanner();
this.typeScanner = new TypeAnnotationScanner(
enableScanSupperClass, enableScanSupperInterface, a -> true, Collections.emptySet()
);
this.methodScanner = new MethodAnnotationScanner(
enableScanSupperClass, enableScanSupperInterface, a -> true, Collections.emptySet()
);
this.elementScanner = new ElementAnnotationScanner();
}
/**
*
*
* @param consumer
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param filter
*/
@Override
public void scan(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
filter = ObjectUtil.defaultIfNull(filter, a -> t -> true);
if (ObjectUtil.isNull(annotatedEle)) {
return;
}
// 注解元素是类
if (annotatedEle instanceof Class) {
scanElements(typeScanner, consumer, annotatedEle, filter);
}
// 注解元素是方法
else if (annotatedEle instanceof Method) {
scanElements(methodScanner, consumer, annotatedEle, filter);
}
// 注解元素是其他类型
else {
scanElements(elementScanner, consumer, annotatedEle, filter);
}
}
/**
*
*
* @param scanner 使
* @param consumer
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param filter
*/
private void scanElements(
AnnotationScanner scanner,
BiConsumer<Integer, Annotation> consumer,
AnnotatedElement annotatedEle,
Predicate<Annotation> filter) {
// 扫描类上注解
final ListValueMap<Integer, Annotation> classAnnotations = new ListValueMap<>(new LinkedHashMap<>());
scanner.scan((index, annotation) -> {
if (filter.test(annotation)) {
classAnnotations.putValue(index, annotation);
}
}, annotatedEle, filter);
// 扫描元注解
classAnnotations.forEach((index, annotations) ->
annotations.forEach(annotation -> {
consumer.accept(index, annotation);
metaScanner.scan(consumer, annotation.annotationType(), filter);
})
);
}
}

View File

@ -0,0 +1,110 @@
package aiyh.utils.tool.cn.hutool.core.annotation.scanner;
import aiyh.utils.tool.cn.hutool.core.annotation.AnnotationUtil;
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
import aiyh.utils.tool.cn.hutool.core.util.ClassUtil;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
*
* {@link TypeAnnotationScanner}
*
* @author huangchengxing
* @see TypeAnnotationScanner
*/
public class MetaAnnotationScanner implements AnnotationScanner {
/**
*
*/
private final boolean includeSupperMetaAnnotation;
/**
*
*
* @param includeSupperMetaAnnotation
*/
public MetaAnnotationScanner(boolean includeSupperMetaAnnotation) {
this.includeSupperMetaAnnotation = includeSupperMetaAnnotation;
}
/**
*
*/
public MetaAnnotationScanner() {
this(true);
}
/**
* {@link Annotation}{@link Class}{@code true}
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @return
*/
@Override
public boolean support(AnnotatedElement annotatedEle) {
return (annotatedEle instanceof Class && ClassUtil.isAssignable(Annotation.class, (Class<?>) annotatedEle));
}
/**
* {@link #support(AnnotatedElement)}true
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @return
*/
@Override
public List<Annotation> getAnnotations(AnnotatedElement annotatedEle) {
final List<Annotation> annotations = new ArrayList<>();
scan(
(index, annotation) -> annotations.add(annotation), annotatedEle,
annotation -> ObjectUtil.notEqual(annotation, annotatedEle)
);
return annotations;
}
/**
* 广
*
* @param consumer
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @param filter
*/
@SuppressWarnings("unchecked")
@Override
public void scan(BiConsumer<Integer, Annotation> consumer, AnnotatedElement annotatedEle, Predicate<Annotation> filter) {
filter = ObjectUtil.defaultIfNull(filter, a -> t -> true);
Set<Class<? extends Annotation>> accessed = new HashSet<>();
final Deque<List<Class<? extends Annotation>>> deque = CollUtil.newLinkedList(CollUtil.newArrayList((Class<? extends Annotation>) annotatedEle));
int distance = 0;
do {
final List<Class<? extends Annotation>> annotationTypes = deque.removeFirst();
for (final Class<? extends Annotation> type : annotationTypes) {
final List<Annotation> metaAnnotations = Stream.of(type.getAnnotations())
.filter(a -> !AnnotationUtil.isJdkMetaAnnotation(a.annotationType()))
.filter(filter)
.collect(Collectors.toList());
for (final Annotation metaAnnotation : metaAnnotations) {
consumer.accept(distance, metaAnnotation);
}
accessed.add(type);
List<Class<? extends Annotation>> next = metaAnnotations.stream()
.map(Annotation::annotationType)
.filter(t -> !accessed.contains(t))
.collect(Collectors.toList());
if (CollUtil.isNotEmpty(next)) {
deque.addLast(next);
}
}
distance++;
} while (includeSupperMetaAnnotation && !deque.isEmpty());
}
}

View File

@ -0,0 +1,133 @@
package aiyh.utils.tool.cn.hutool.core.annotation.scanner;
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
import aiyh.utils.tool.cn.hutool.core.util.ArrayUtil;
import aiyh.utils.tool.cn.hutool.core.util.ClassUtil;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* {@link Method}
*
* @author huangchengxing
*/
public class MethodAnnotationScanner extends AbstractTypeAnnotationScanner<MethodAnnotationScanner> implements AnnotationScanner {
/**
*
*/
public MethodAnnotationScanner() {
this(false);
}
/**
*
*
* @param scanSameSignatureMethod
*/
public MethodAnnotationScanner(boolean scanSameSignatureMethod) {
this(scanSameSignatureMethod, targetClass -> true, CollUtil.newLinkedHashSet());
}
/**
*
*
* @param scanSameSignatureMethod
* @param filter
* @param excludeTypes
*/
public MethodAnnotationScanner(boolean scanSameSignatureMethod, Predicate<Class<?>> filter, Set<Class<?>> excludeTypes) {
super(scanSameSignatureMethod, scanSameSignatureMethod, filter, excludeTypes);
}
/**
*
*
* @param includeSuperClass
* @param includeInterfaces
* @param filter
* @param excludeTypes
*/
public MethodAnnotationScanner(boolean includeSuperClass, boolean includeInterfaces, Predicate<Class<?>> filter, Set<Class<?>> excludeTypes) {
super(includeSuperClass, includeInterfaces, filter, excludeTypes);
}
/**
* {@link Method}{@code true}
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @return boolean
*/
@Override
public boolean support(AnnotatedElement annotatedEle) {
return annotatedEle instanceof Method;
}
/**
*
*
* @param annotatedElement
* @return
* @see Method#getDeclaringClass()
*/
@Override
protected Class<?> getClassFormAnnotatedElement(AnnotatedElement annotatedElement) {
return ((Method)annotatedElement).getDeclaringClass();
}
/**
* /
*
* @param source
* @param index
* @param targetClass
* @return
*/
@Override
protected Annotation[] getAnnotationsFromTargetClass(AnnotatedElement source, int index, Class<?> targetClass) {
final Method sourceMethod = (Method) source;
return Stream.of(ClassUtil.getDeclaredMethods(targetClass))
.filter(superMethod -> !superMethod.isBridge())
.filter(superMethod -> hasSameSignature(sourceMethod, superMethod))
.map(AnnotatedElement::getAnnotations)
.flatMap(Stream::of)
.toArray(Annotation[]::new);
}
/**
*
*
* @param scanSuperMethodIfOverride
* @return
*/
public MethodAnnotationScanner setScanSameSignatureMethod(boolean scanSuperMethodIfOverride) {
setIncludeInterfaces(scanSuperMethodIfOverride);
setIncludeSuperClass(scanSuperMethodIfOverride);
return this;
}
/**
*
*/
private boolean hasSameSignature(Method sourceMethod, Method superMethod) {
if (false == StrUtil.equals(sourceMethod.getName(), superMethod.getName())) {
return false;
}
final Class<?>[] sourceParameterTypes = sourceMethod.getParameterTypes();
final Class<?>[] targetParameterTypes = superMethod.getParameterTypes();
if (sourceParameterTypes.length != targetParameterTypes.length) {
return false;
}
if (!ArrayUtil.containsAll(sourceParameterTypes, targetParameterTypes)) {
return false;
}
return ClassUtil.isAssignable(superMethod.getReturnType(), sourceMethod.getReturnType());
}
}

View File

@ -0,0 +1,105 @@
package aiyh.utils.tool.cn.hutool.core.annotation.scanner;
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Proxy;
import java.util.Set;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
/**
* {@link Class}
*
* @author huangchengxing
*/
public class TypeAnnotationScanner extends AbstractTypeAnnotationScanner<TypeAnnotationScanner> implements AnnotationScanner {
/**
*
*
* @param includeSupperClass
* @param includeInterfaces
* @param filter
* @param excludeTypes
*/
public TypeAnnotationScanner(boolean includeSupperClass, boolean includeInterfaces, Predicate<Class<?>> filter, Set<Class<?>> excludeTypes) {
super(includeSupperClass, includeInterfaces, filter, excludeTypes);
}
/**
*
*/
public TypeAnnotationScanner() {
this(true, true, t -> true, CollUtil.newLinkedHashSet());
}
/**
* {@link Class}{@code true}
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @return
*/
@Override
public boolean support(AnnotatedElement annotatedEle) {
return annotatedEle instanceof Class;
}
/**
* {@link Class}
*
* @param annotatedEle {@link AnnotatedElement}ClassMethodFieldConstructorReflectPermission
* @return
*/
@Override
protected Class<?> getClassFormAnnotatedElement(AnnotatedElement annotatedEle) {
return (Class<?>)annotatedEle;
}
/**
* {@link Class#getAnnotations()}
*
* @param source
* @param index
* @param targetClass
* @return
*/
@Override
protected Annotation[] getAnnotationsFromTargetClass(AnnotatedElement source, int index, Class<?> targetClass) {
return targetClass.getAnnotations();
}
/**
*
*
* @param includeSuperClass
* @return
*/
@Override
public TypeAnnotationScanner setIncludeSuperClass(boolean includeSuperClass) {
return super.setIncludeSuperClass(includeSuperClass);
}
/**
*
*
* @param includeInterfaces
* @return
*/
@Override
public TypeAnnotationScanner setIncludeInterfaces(boolean includeInterfaces) {
return super.setIncludeInterfaces(includeInterfaces);
}
/**
* jdk
*/
public static class JdkProxyClassConverter implements UnaryOperator<Class<?>> {
@Override
public Class<?> apply(Class<?> sourceClass) {
return Proxy.isProxyClass(sourceClass) ? apply(sourceClass.getSuperclass()) : sourceClass;
}
}
}

View File

@ -0,0 +1,7 @@
/**
*
*
* @author looly
*
*/
package aiyh.utils.tool.cn.hutool.core.annotation.scanner;

View File

@ -0,0 +1,324 @@
package aiyh.utils.tool.cn.hutool.core.bean;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.map.CaseInsensitiveMap;
import aiyh.utils.tool.cn.hutool.core.util.BooleanUtil;
import aiyh.utils.tool.cn.hutool.core.util.ModifierUtil;
import aiyh.utils.tool.cn.hutool.core.util.ReflectUtil;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* BeanBeanInfoJavaBeansettersgetters<br>
* GetterSetter
*
* <pre>
* 1.
* 2. GettergetXXXisXXXgetIsXXX
* 3. SettersetXXXsetIsXXX
* 4. Setter
* </pre>
*
* @author looly
* @since 3.1.2
*/
public class BeanDesc implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Bean
*/
private final Class<?> beanClass;
/**
* Map
*/
private final Map<String, PropDesc> propMap = new LinkedHashMap<>();
/**
*
*
* @param beanClass Bean
*/
public BeanDesc(Class<?> beanClass) {
Assert.notNull(beanClass);
this.beanClass = beanClass;
init();
}
/**
* Bean
*
* @return Bean
*/
public String getName() {
return this.beanClass.getName();
}
/**
* Bean
*
* @return Bean
*/
public String getSimpleName() {
return this.beanClass.getSimpleName();
}
/**
* -Map
*
* @param ignoreCase truefalse
* @return -Map
*/
public Map<String, PropDesc> getPropMap(boolean ignoreCase) {
return ignoreCase ? new CaseInsensitiveMap<>(1, this.propMap) : this.propMap;
}
/**
*
*
* @return {@link PropDesc}
*/
public Collection<PropDesc> getProps() {
return this.propMap.values();
}
/**
* null
*
* @param fieldName
* @return {@link PropDesc}
*/
public PropDesc getProp(String fieldName) {
return this.propMap.get(fieldName);
}
/**
* null
*
* @param fieldName
* @return
*/
public Field getField(String fieldName) {
final PropDesc desc = this.propMap.get(fieldName);
return null == desc ? null : desc.getField();
}
/**
* Getternull
*
* @param fieldName
* @return Getter
*/
public Method getGetter(String fieldName) {
final PropDesc desc = this.propMap.get(fieldName);
return null == desc ? null : desc.getGetter();
}
/**
* Setternull
*
* @param fieldName
* @return Setter
*/
public Method getSetter(String fieldName) {
final PropDesc desc = this.propMap.get(fieldName);
return null == desc ? null : desc.getSetter();
}
// ------------------------------------------------------------------------------------------------------ Private method start
/**
* <br>
* GetterSettergetXXXsetXXX
*
* @return this
*/
private BeanDesc init() {
final Method[] gettersAndSetters = ReflectUtil.getMethods(this.beanClass, ReflectUtil::isGetterOrSetterIgnoreCase);
PropDesc prop;
for (Field field : ReflectUtil.getFields(this.beanClass)) {
// 排除静态属性和对象子类
if (false == ModifierUtil.isStatic(field) && false == ReflectUtil.isOuterClassField(field)) {
prop = createProp(field, gettersAndSetters);
// 只有不存在时才放入,防止父类属性覆盖子类属性
this.propMap.putIfAbsent(prop.getFieldName(), prop);
}
}
return this;
}
/**
* <br>
* GetterSetter
*
* <pre>
* 1.
* 2. GettergetXXXisXXXgetIsXXX
* 3. SettersetXXXsetIsXXX
* 4. Setter
* </pre>
*
* @param field
* @param methods
* @return {@link PropDesc}
* @since 4.0.2
*/
private PropDesc createProp(Field field, Method[] methods) {
final PropDesc prop = findProp(field, methods, false);
// 忽略大小写重新匹配一次
if (null == prop.getter || null == prop.setter) {
final PropDesc propIgnoreCase = findProp(field, methods, true);
if (null == prop.getter) {
prop.getter = propIgnoreCase.getter;
}
if (null == prop.setter) {
prop.setter = propIgnoreCase.setter;
}
}
return prop;
}
/**
* GetterSetter
*
* @param field
* @param gettersOrSetters GetterSetter
* @param ignoreCase
* @return PropDesc
*/
private PropDesc findProp(Field field, Method[] gettersOrSetters, boolean ignoreCase) {
final String fieldName = field.getName();
final Class<?> fieldType = field.getType();
final boolean isBooleanField = BooleanUtil.isBoolean(fieldType);
Method getter = null;
Method setter = null;
String methodName;
for (Method method : gettersOrSetters) {
methodName = method.getName();
if (method.getParameterCount() == 0) {
// 无参数可能为Getter方法
if (isMatchGetter(methodName, fieldName, isBooleanField, ignoreCase)) {
// 方法名与字段名匹配则为Getter方法
getter = method;
}
} else if (isMatchSetter(methodName, fieldName, isBooleanField, ignoreCase)) {
// setter方法的参数类型和字段类型必须一致或参数类型是字段类型的子类
if(fieldType.isAssignableFrom(method.getParameterTypes()[0])){
setter = method;
}
}
if (null != getter && null != setter) {
// 如果Getter和Setter方法都找到了不再继续寻找
break;
}
}
return new PropDesc(field, getter, setter);
}
/**
* Getter<br>
*
*
* <pre>
* -
* isName - isName
* isName - isIsName
* isName - getIsName
* name - isName
* name - getName
* </pre>
*
* @param methodName
* @param fieldName
* @param isBooleanField Boolean
* @param ignoreCase
* @return
*/
private boolean isMatchGetter(String methodName, String fieldName, boolean isBooleanField, boolean ignoreCase) {
final String handledFieldName;
if (ignoreCase) {
// 全部转为小写,忽略大小写比较
methodName = methodName.toLowerCase();
handledFieldName = fieldName.toLowerCase();
fieldName = handledFieldName;
} else {
handledFieldName = StrUtil.upperFirst(fieldName);
}
// 针对Boolean类型特殊检查
if (isBooleanField) {
if (fieldName.startsWith("is")) {
// 字段已经是is开头
if (methodName.equals(fieldName) // isName -》 isName
|| ("get" + handledFieldName).equals(methodName)// isName -》 getIsName
|| ("is" + handledFieldName).equals(methodName)// isName -》 isIsName
) {
return true;
}
} else if (("is" + handledFieldName).equals(methodName)) {
// 字段非is开头 name -》 isName
return true;
}
}
// 包括boolean的任何类型只有一种匹配情况name -》 getName
return ("get" + handledFieldName).equals(methodName);
}
/**
* Setter<br>
*
*
* <pre>
* -
* isName - setName
* isName - setIsName
* name - setName
* </pre>
*
* @param methodName
* @param fieldName
* @param isBooleanField Boolean
* @param ignoreCase
* @return
*/
private boolean isMatchSetter(String methodName, String fieldName, boolean isBooleanField, boolean ignoreCase) {
final String handledFieldName;
if (ignoreCase) {
// 全部转为小写,忽略大小写比较
methodName = methodName.toLowerCase();
handledFieldName = fieldName.toLowerCase();
fieldName = handledFieldName;
} else {
handledFieldName = StrUtil.upperFirst(fieldName);
}
// 非标准Setter方法跳过
if (false == methodName.startsWith("set")) {
return false;
}
// 针对Boolean类型特殊检查
if (isBooleanField && fieldName.startsWith("is")) {
// 字段是is开头
if (("set" + StrUtil.removePrefix(fieldName, "is")).equals(methodName)// isName -》 setName
|| ("set" + handledFieldName).equals(methodName)// isName -》 setIsName
) {
return true;
}
}
// 包括boolean的任何类型只有一种匹配情况name -》 setName
return ("set" + handledFieldName).equals(methodName);
}
// ------------------------------------------------------------------------------------------------------ Private method end
}

View File

@ -0,0 +1,37 @@
package aiyh.utils.tool.cn.hutool.core.bean;
import aiyh.utils.tool.cn.hutool.core.lang.func.Func0;
import aiyh.utils.tool.cn.hutool.core.map.WeakConcurrentMap;
/**
* Bean<br>
*
*
* @author Looly
*/
public enum BeanDescCache {
INSTANCE;
private final WeakConcurrentMap<Class<?>, BeanDesc> bdCache = new WeakConcurrentMap<>();
/**
* {@link BeanDesc}Map
*
* @param beanClass Bean
* @param supplier
* @return {@link BeanDesc}
* @since 5.4.2
*/
public BeanDesc getBeanDesc(Class<?> beanClass, Func0<BeanDesc> supplier) {
return bdCache.computeIfAbsent(beanClass, (key)->supplier.callWithRuntimeException());
}
/**
* Bean
*
* @since 5.7.21
*/
public void clear() {
this.bdCache.clear();
}
}

View File

@ -0,0 +1,32 @@
package aiyh.utils.tool.cn.hutool.core.bean;
import aiyh.utils.tool.cn.hutool.core.exceptions.ExceptionUtil;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
/**
* Bean
* @author xiaoleilu
*/
public class BeanException extends RuntimeException{
private static final long serialVersionUID = -8096998667745023423L;
public BeanException(Throwable e) {
super(ExceptionUtil.getMessage(e), e);
}
public BeanException(String message) {
super(message);
}
public BeanException(String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params));
}
public BeanException(String message, Throwable throwable) {
super(message, throwable);
}
public BeanException(Throwable throwable, String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params), throwable);
}
}

View File

@ -0,0 +1,80 @@
package aiyh.utils.tool.cn.hutool.core.bean;
import aiyh.utils.tool.cn.hutool.core.lang.func.Func0;
import aiyh.utils.tool.cn.hutool.core.map.ReferenceConcurrentMap;
import aiyh.utils.tool.cn.hutool.core.map.WeakConcurrentMap;
import java.beans.PropertyDescriptor;
import java.util.Map;
/**
* Bean<br>
*
*
* @author Looly
*/
public enum BeanInfoCache {
INSTANCE;
private final WeakConcurrentMap<Class<?>, Map<String, PropertyDescriptor>> pdCache = new WeakConcurrentMap<>();
private final WeakConcurrentMap<Class<?>, Map<String, PropertyDescriptor>> ignoreCasePdCache = new WeakConcurrentMap<>();
/**
* {@link PropertyDescriptor}Map
*
* @param beanClass Bean
* @param ignoreCase
* @return {@link PropertyDescriptor}Map
*/
public Map<String, PropertyDescriptor> getPropertyDescriptorMap(Class<?> beanClass, boolean ignoreCase) {
return getCache(ignoreCase).get(beanClass);
}
/**
* {@link PropertyDescriptor}Map
*
* @param beanClass Bean
* @param ignoreCase
* @param supplier
* @return {@link PropertyDescriptor}Map
* @since 5.4.1
*/
public Map<String, PropertyDescriptor> getPropertyDescriptorMap(
Class<?> beanClass,
boolean ignoreCase,
Func0<Map<String, PropertyDescriptor>> supplier) {
return getCache(ignoreCase).computeIfAbsent(beanClass, (key)->supplier.callWithRuntimeException());
}
/**
*
*
* @param beanClass Bean
* @param fieldNamePropertyDescriptorMap {@link PropertyDescriptor}Map
* @param ignoreCase
*/
public void putPropertyDescriptorMap(Class<?> beanClass, Map<String, PropertyDescriptor> fieldNamePropertyDescriptorMap, boolean ignoreCase) {
getCache(ignoreCase).put(beanClass, fieldNamePropertyDescriptorMap);
}
/**
*
*
* @since 5.7.21
*/
public void clear() {
this.pdCache.clear();
this.ignoreCasePdCache.clear();
}
/**
* Cache
*
* @param ignoreCase
* @return {@link ReferenceConcurrentMap}
* @since 5.4.1
*/
private ReferenceConcurrentMap<Class<?>, Map<String, PropertyDescriptor>> getCache(boolean ignoreCase) {
return ignoreCase ? ignoreCasePdCache : pdCache;
}
}

View File

@ -0,0 +1,324 @@
package aiyh.utils.tool.cn.hutool.core.bean;
import aiyh.utils.tool.cn.hutool.core.collection.CollUtil;
import aiyh.utils.tool.cn.hutool.core.collection.ListUtil;
import aiyh.utils.tool.cn.hutool.core.convert.Convert;
import aiyh.utils.tool.cn.hutool.core.map.MapUtil;
import aiyh.utils.tool.cn.hutool.core.util.ArrayUtil;
import aiyh.utils.tool.cn.hutool.core.util.CharUtil;
import aiyh.utils.tool.cn.hutool.core.util.NumberUtil;
import aiyh.utils.tool.cn.hutool.core.util.StrUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* BeanBeanBean<br>
* Bean
* <ol>
* <li>.BeanMapkey</li>
* <li>[]index</li>
* </ol>
* <p>
*
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* ['person']['friends'][5]['name']
* </pre>
*
* @author Looly
* @since 4.0.6
*/
public class BeanPath implements Serializable {
private static final long serialVersionUID = 1L;
/**
*
*/
private static final char[] EXP_CHARS = {CharUtil.DOT, CharUtil.BRACKET_START, CharUtil.BRACKET_END};
private boolean isStartWith = false;
protected List<String> patternParts;
/**
* BeanBean<br>
* BeanBeanBean<br>
* Bean
* <ol>
* <li>.BeanMapkey</li>
* <li>[]index</li>
* </ol>
* <p>
*
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* ['person']['friends'][5]['name']
* </pre>
*
* @param expression
* @return BeanPath
*/
public static BeanPath create(final String expression) {
return new BeanPath(expression);
}
/**
*
*
* @param expression
*/
public BeanPath(final String expression) {
init(expression);
}
/**
*
*
* @return
*/
public List<String> getPatternParts() {
return this.patternParts;
}
/**
* Bean
*
* @param bean BeanMapList
* @return null
*/
public Object get(final Object bean) {
return get(this.patternParts, bean, false);
}
/**
* filed<br>
* ListMapputkeyBean<br>
*
*
* <pre>
* 1. ListList
* 2.
* </pre>
*
* @param bean BeanMapList
* @param value
*/
public void set(final Object bean, final Object value) {
set(bean, this.patternParts, lastIsNumber(this.patternParts), value);
}
@Override
public String toString() {
return this.patternParts.toString();
}
//region Private Methods
/**
* filed<br>
* ListMapputkeyBean<br>
*
*
* <pre>
* 1. ListList
* 2.
* </pre>
*
* @param bean BeanMapList
* @param patternParts
* @param value
* @return
*/
private void set(Object bean, List<String> patternParts, boolean nextNumberPart, Object value) {
Object subBean = this.get(patternParts, bean, true);
if (null == subBean) {
final List<String> parentParts = getParentParts(patternParts);
this.set(bean, parentParts, lastIsNumber(parentParts), nextNumberPart ? new ArrayList<>() : new HashMap<>());
//set中有可能做过转换因此此处重新获取bean
subBean = this.get(patternParts, bean, true);
}
BeanUtil.setFieldValue(subBean, patternParts.get(patternParts.size() - 1), value);
}
/**
* path
*
* @param patternParts path
* @return
*/
private static boolean lastIsNumber(List<String> patternParts) {
return NumberUtil.isInteger(patternParts.get(patternParts.size() - 1));
}
/**
*
*
* @param patternParts
* @return
*/
private static List<String> getParentParts(List<String> patternParts) {
return patternParts.subList(0, patternParts.size() - 1);
}
/**
* Bean
*
* @param patternParts
* @param bean BeanMapList
* @param ignoreLast setread
* @return null
*/
private Object get(final List<String> patternParts, final Object bean, final boolean ignoreLast) {
int length = patternParts.size();
if (ignoreLast) {
length--;
}
Object subBean = bean;
boolean isFirst = true;
String patternPart;
for (int i = 0; i < length; i++) {
patternPart = patternParts.get(i);
subBean = getFieldValue(subBean, patternPart);
if (null == subBean) {
// 支持表达式的第一个对象为Bean本身若用户定义表达式$开头,则不做此操作)
if (isFirst && false == this.isStartWith && BeanUtil.isMatchName(bean, patternPart, true)) {
subBean = bean;
isFirst = false;
} else {
return null;
}
}
}
return subBean;
}
@SuppressWarnings("unchecked")
private static Object getFieldValue(final Object bean, final String expression) {
if (StrUtil.isBlank(expression)) {
return null;
}
if (StrUtil.contains(expression, ':')) {
// [start:end:step] 模式
final List<String> parts = StrUtil.splitTrim(expression, ':');
final int start = Integer.parseInt(parts.get(0));
final int end = Integer.parseInt(parts.get(1));
int step = 1;
if (3 == parts.size()) {
step = Integer.parseInt(parts.get(2));
}
if (bean instanceof Collection) {
return CollUtil.sub((Collection<?>) bean, start, end, step);
} else if (ArrayUtil.isArray(bean)) {
return ArrayUtil.sub(bean, start, end, step);
}
} else if (StrUtil.contains(expression, ',')) {
// [num0,num1,num2...]模式或者['key0','key1']模式
final List<String> keys = StrUtil.splitTrim(expression, ',');
if (bean instanceof Collection) {
return CollUtil.getAny((Collection<?>) bean, Convert.convert(int[].class, keys));
} else if (ArrayUtil.isArray(bean)) {
return ArrayUtil.getAny(bean, Convert.convert(int[].class, keys));
} else {
final String[] unWrappedKeys = new String[keys.size()];
for (int i = 0; i < unWrappedKeys.length; i++) {
unWrappedKeys[i] = StrUtil.unWrap(keys.get(i), '\'');
}
if (bean instanceof Map) {
// 只支持String为key的Map
return MapUtil.getAny((Map<String, ?>) bean, unWrappedKeys);
} else {
final Map<String, Object> map = BeanUtil.beanToMap(bean);
return MapUtil.getAny(map, unWrappedKeys);
}
}
} else {
// 数字或普通字符串
return BeanUtil.getFieldValue(bean, expression);
}
return null;
}
/**
*
*
* @param expression
*/
private void init(final String expression) {
final List<String> localPatternParts = new ArrayList<>();
final int length = expression.length();
final StringBuilder builder = new StringBuilder();
char c;
boolean isNumStart = false;// 下标标识符开始
boolean isInWrap = false; //标识是否在引号内
for (int i = 0; i < length; i++) {
c = expression.charAt(i);
if (0 == i && '$' == c) {
// 忽略开头的$符,表示当前对象
isStartWith = true;
continue;
}
if ('\'' == c) {
// 结束
isInWrap = (false == isInWrap);
continue;
}
if (false == isInWrap && ArrayUtil.contains(EXP_CHARS, c)) {
// 处理边界符号
if (CharUtil.BRACKET_END == c) {
// 中括号(数字下标)结束
if (false == isNumStart) {
throw new IllegalArgumentException(StrUtil.format("Bad expression '{}':{}, we find ']' but no '[' !", expression, i));
}
isNumStart = false;
// 中括号结束加入下标
} else {
if (isNumStart) {
// 非结束中括号情况下发现起始中括号报错(中括号未关闭)
throw new IllegalArgumentException(StrUtil.format("Bad expression '{}':{}, we find '[' but no ']' !", expression, i));
} else if (CharUtil.BRACKET_START == c) {
// 数字下标开始
isNumStart = true;
}
// 每一个边界符之前的表达式是一个完整的KEY开始处理KEY
}
if (builder.length() > 0) {
localPatternParts.add(builder.toString());
}
builder.setLength(0);
} else {
// 非边界符号,追加字符
builder.append(c);
}
}
// 末尾边界符检查
if (isNumStart) {
throw new IllegalArgumentException(StrUtil.format("Bad expression '{}':{}, we find '[' but no ']' !", expression, length - 1));
} else {
if (builder.length() > 0) {
localPatternParts.add(builder.toString());
}
}
// 不可变List
this.patternParts = ListUtil.unmodifiable(localPatternParts);
}
//endregion
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,226 @@
package aiyh.utils.tool.cn.hutool.core.bean;
import aiyh.utils.tool.cn.hutool.core.clone.CloneSupport;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.util.ClassUtil;
import aiyh.utils.tool.cn.hutool.core.util.ReflectUtil;
import java.io.Serializable;
import java.util.Map;
/**
* BeanBean<br>
* MapBean
*
* @author Looly
* @since 3.0.7
*/
public class DynaBean extends CloneSupport<DynaBean> implements Serializable {
private static final long serialVersionUID = 1L;
private final Class<?> beanClass;
private final Object bean;
/**
* DynaBean
*
* @param bean Bean
* @return DynaBean
*/
public static DynaBean create(Object bean) {
return new DynaBean(bean);
}
/**
* DynaBean
*
* @param beanClass Bean
* @return DynaBean
*/
public static DynaBean create(Class<?> beanClass) {
return new DynaBean(beanClass);
}
/**
* DynaBean
*
* @param beanClass Bean
* @param params Bean
* @return DynaBean
*/
public static DynaBean create(Class<?> beanClass, Object... params) {
return new DynaBean(beanClass, params);
}
//------------------------------------------------------------------------ Constructor start
/**
*
*
* @param beanClass Bean
* @param params Bean
*/
public DynaBean(Class<?> beanClass, Object... params) {
this(ReflectUtil.newInstance(beanClass, params));
}
/**
*
*
* @param beanClass Bean
*/
public DynaBean(Class<?> beanClass) {
this(ReflectUtil.newInstance(beanClass));
}
/**
*
*
* @param bean Bean
*/
public DynaBean(Object bean) {
Assert.notNull(bean);
if (bean instanceof DynaBean) {
bean = ((DynaBean) bean).getBean();
}
this.bean = bean;
this.beanClass = ClassUtil.getClass(bean);
}
//------------------------------------------------------------------------ Constructor end
/**
*
*
* @param <T>
* @param fieldName
* @return
* @throws BeanException
*/
@SuppressWarnings("unchecked")
public <T> T get(String fieldName) throws BeanException {
if (Map.class.isAssignableFrom(beanClass)) {
return (T) ((Map<?, ?>) bean).get(fieldName);
} else {
final PropDesc prop = BeanUtil.getBeanDesc(beanClass).getProp(fieldName);
if (null == prop) {
throw new BeanException("No public field or get method for {}", fieldName);
}
return (T) prop.getValue(bean);
}
}
/**
* bean
*
* @param fieldName
* @return bean
* @since 5.4.2
*/
public boolean containsProp(String fieldName) {
if (Map.class.isAssignableFrom(beanClass)) {
return ((Map<?, ?>) bean).containsKey(fieldName);
} else{
return null != BeanUtil.getBeanDesc(beanClass).getProp(fieldName);
}
}
/**
* {@code null}
*
* @param <T>
* @param fieldName
* @return
* @since 3.1.1
*/
public <T> T safeGet(String fieldName) {
try {
return get(fieldName);
} catch (Exception e) {
return null;
}
}
/**
*
*
* @param fieldName
* @param value
* @throws BeanException
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public void set(String fieldName, Object value) throws BeanException {
if (Map.class.isAssignableFrom(beanClass)) {
((Map) bean).put(fieldName, value);
} else {
final PropDesc prop = BeanUtil.getBeanDesc(beanClass).getProp(fieldName);
if (null == prop) {
throw new BeanException("No public field or set method for {}", fieldName);
}
prop.setValue(bean, value);
}
}
/**
* Bean
*
* @param methodName
* @param params
* @return null
*/
public Object invoke(String methodName, Object... params) {
return ReflectUtil.invoke(this.bean, methodName, params);
}
/**
* Bean
*
* @param <T> Bean
* @return bean
*/
@SuppressWarnings("unchecked")
public <T> T getBean() {
return (T) this.bean;
}
/**
* Bean
*
* @param <T> Bean
* @return Bean
*/
@SuppressWarnings("unchecked")
public <T> Class<T> getBeanClass() {
return (Class<T>) this.beanClass;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((bean == null) ? 0 : bean.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final DynaBean other = (DynaBean) obj;
if (bean == null) {
return other.bean == null;
} else return bean.equals(other.bean);
}
@Override
public String toString() {
return this.bean.toString();
}
}

View File

@ -0,0 +1,29 @@
package aiyh.utils.tool.cn.hutool.core.bean;
/**
* ,null,
*
* @param <T> Null
* @author Lillls
* @since 5.5.0
*/
public class NullWrapperBean<T> {
private final Class<T> clazz;
/**
* @param clazz null
*/
public NullWrapperBean(Class<T> clazz) {
this.clazz = clazz;
}
/**
* null
*
* @return
*/
public Class<T> getWrappedClass() {
return clazz;
}
}

View File

@ -0,0 +1,404 @@
package aiyh.utils.tool.cn.hutool.core.bean;
import aiyh.utils.tool.cn.hutool.core.annotation.AnnotationUtil;
import aiyh.utils.tool.cn.hutool.core.annotation.PropIgnore;
import aiyh.utils.tool.cn.hutool.core.convert.Convert;
import aiyh.utils.tool.cn.hutool.core.util.ClassUtil;
import aiyh.utils.tool.cn.hutool.core.util.ModifierUtil;
import aiyh.utils.tool.cn.hutool.core.util.ReflectUtil;
import aiyh.utils.tool.cn.hutool.core.util.TypeUtil;
import java.beans.Transient;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
/**
* gettersetter
*
* @author looly
*/
public class PropDesc {
/**
*
*/
final Field field;
/**
* Getter
*/
protected Method getter;
/**
* Setter
*/
protected Method setter;
/**
* <br>
* GetterSetter访
*
* @param field
* @param getter get
* @param setter set
*/
public PropDesc(Field field, Method getter, Method setter) {
this.field = field;
this.getter = ClassUtil.setAccessible(getter);
this.setter = ClassUtil.setAccessible(setter);
}
/**
* Alias
*
* @return
*/
public String getFieldName() {
return ReflectUtil.getFieldName(this.field);
}
/**
*
*
* @return
* @since 5.1.6
*/
public String getRawFieldName() {
return null == this.field ? null : this.field.getName();
}
/**
*
*
* @return
*/
public Field getField() {
return this.field;
}
/**
* <br>
* GetterSetter
*
* @return
*/
public Type getFieldType() {
if (null != this.field) {
return TypeUtil.getType(this.field);
}
return findPropType(getter, setter);
}
/**
* <br>
* GetterSetter
*
* @return
*/
public Class<?> getFieldClass() {
if (null != this.field) {
return TypeUtil.getClass(this.field);
}
return findPropClass(getter, setter);
}
/**
* Getter{@code null}
*
* @return Getter
*/
public Method getGetter() {
return this.getter;
}
/**
* Setter{@code null}
*
* @return {@link Method}Setter
*/
public Method getSetter() {
return this.setter;
}
/**
* {@link #getValue(Object)}
*
* @param checkTransient Transient
* @return
* @since 5.4.2
*/
public boolean isReadable(boolean checkTransient) {
// 检查是否有getter方法或是否为public修饰
if (null == this.getter && false == ModifierUtil.isPublic(this.field)) {
return false;
}
// 检查transient关键字和@Transient注解
if (checkTransient && isTransientForGet()) {
return false;
}
// 检查@PropIgnore注解
return false == isIgnoreGet();
}
/**
* <br>
* GetterGetterpublic<br>
* 使 {@link #isReadable(boolean)}
*
* @param bean Bean
* @return
* @since 4.0.5
*/
public Object getValue(Object bean) {
if (null != this.getter) {
return ReflectUtil.invoke(bean, this.getter);
} else if (ModifierUtil.isPublic(this.field)) {
return ReflectUtil.getFieldValue(bean, this.field);
}
return null;
}
/**
* <br>
* GetterGetterpublic
*
* @param bean Bean
* @param targetType null
* @param ignoreError
* @return this
* @since 5.4.2
*/
public Object getValue(Object bean, Type targetType, boolean ignoreError) {
Object result = null;
try {
result = getValue(bean);
} catch (Exception e) {
if (false == ignoreError) {
throw new BeanException(e, "Get value of [{}] error!", getFieldName());
}
}
if (null != result && null != targetType) {
// 尝试将结果转换为目标类型如果转换失败返回null即跳过此属性值。
// 来自issues#I41WKP@Gitee当忽略错误情况下目标类型转换失败应返回null
// 如果返回原值,在集合注入时会成功,但是集合取值时会报类型转换错误
return Convert.convertWithCheck(targetType, result, null, ignoreError);
}
return result;
}
/**
* {@link #getValue(Object)}
*
* @param checkTransient Transient
* @return
* @since 5.4.2
*/
public boolean isWritable(boolean checkTransient) {
// 检查是否有getter方法或是否为public修饰
if (null == this.setter && false == ModifierUtil.isPublic(this.field)) {
return false;
}
// 检查transient关键字和@Transient注解
if (checkTransient && isTransientForSet()) {
return false;
}
// 检查@PropIgnore注解
return false == isIgnoreSet();
}
/**
* Bean<br>
* SetterSetterpublic<br>
* 使 {@link #isWritable(boolean)}
*
* @param bean Bean
* @param value
* @return this
* @since 4.0.5
*/
public PropDesc setValue(Object bean, Object value) {
if (null != this.setter) {
ReflectUtil.invoke(bean, this.setter, value);
} else if (ModifierUtil.isPublic(this.field)) {
ReflectUtil.setFieldValue(bean, this.field, value);
}
return this;
}
/**
*
*
* @param bean Bean
* @param value
* @param ignoreNull {@code null}true
* @param ignoreError
* @return this
* @since 5.4.2
*/
public PropDesc setValue(Object bean, Object value, boolean ignoreNull, boolean ignoreError) {
return setValue(bean, value, ignoreNull, ignoreError, true);
}
/**
*
*
* @param bean Bean
* @param value
* @param ignoreNull {@code null}true
* @param ignoreError
* @param override bean{@code null}
* @return this
* @since 5.7.17
*/
public PropDesc setValue(Object bean, Object value, boolean ignoreNull, boolean ignoreError, boolean override) {
if (null == value && ignoreNull) {
return this;
}
// issue#I4JQ1N@Gitee
// 非覆盖模式下,如果目标值存在,则跳过
if (false == override && null != getValue(bean)) {
return this;
}
// 当类型不匹配的时候,执行默认转换
if (null != value) {
final Class<?> propClass = getFieldClass();
if (false == propClass.isInstance(value)) {
value = Convert.convertWithCheck(propClass, value, null, ignoreError);
}
}
// 属性赋值
if (null != value || false == ignoreNull) {
try {
this.setValue(bean, value);
} catch (Exception e) {
if (false == ignoreError) {
throw new BeanException(e, "Set value of [{}] error!", getFieldName());
}
// 忽略注入失败
}
}
return this;
}
//------------------------------------------------------------------------------------ Private method start
/**
* GetterSetter
*
* @param getter Getter
* @param setter Setter
* @return {@link Type}
*/
private Type findPropType(Method getter, Method setter) {
Type type = null;
if (null != getter) {
type = TypeUtil.getReturnType(getter);
}
if (null == type && null != setter) {
type = TypeUtil.getParamType(setter, 0);
}
return type;
}
/**
* GetterSetter
*
* @param getter Getter
* @param setter Setter
* @return {@link Type}
*/
private Class<?> findPropClass(Method getter, Method setter) {
Class<?> type = null;
if (null != getter) {
type = TypeUtil.getReturnClass(getter);
}
if (null == type && null != setter) {
type = TypeUtil.getFirstParamClass(setter);
}
return type;
}
/**
* {@link PropIgnore}
* <pre>
* 1. {@link PropIgnore}
* 2. setXXX{@link PropIgnore}
* </pre>
*
* @return
* @since 5.4.2
*/
private boolean isIgnoreSet() {
return AnnotationUtil.hasAnnotation(this.field, PropIgnore.class)
|| AnnotationUtil.hasAnnotation(this.setter, PropIgnore.class);
}
/**
* {@link PropIgnore}
* <pre>
* 1. {@link PropIgnore}
* 2. getXXX{@link PropIgnore}
* </pre>
*
* @return
* @since 5.4.2
*/
private boolean isIgnoreGet() {
return AnnotationUtil.hasAnnotation(this.field, PropIgnore.class)
|| AnnotationUtil.hasAnnotation(this.getter, PropIgnore.class);
}
/**
* GetterTransient
*
* @return Transient
* @since 5.3.11
*/
private boolean isTransientForGet() {
boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierUtil.ModifierType.TRANSIENT);
// 检查Getter方法
if (false == isTransient && null != this.getter) {
isTransient = ModifierUtil.hasModifier(this.getter, ModifierUtil.ModifierType.TRANSIENT);
// 检查注解
if (false == isTransient) {
isTransient = AnnotationUtil.hasAnnotation(this.getter, Transient.class);
}
}
return isTransient;
}
/**
* GetterTransient
*
* @return Transient
* @since 5.3.11
*/
private boolean isTransientForSet() {
boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierUtil.ModifierType.TRANSIENT);
// 检查Getter方法
if (false == isTransient && null != this.setter) {
isTransient = ModifierUtil.hasModifier(this.setter, ModifierUtil.ModifierType.TRANSIENT);
// 检查注解
if (false == isTransient) {
isTransient = AnnotationUtil.hasAnnotation(this.setter, Transient.class);
}
}
return isTransient;
}
//------------------------------------------------------------------------------------ Private method end
}

View File

@ -0,0 +1,28 @@
package aiyh.utils.tool.cn.hutool.core.bean.copier;
import aiyh.utils.tool.cn.hutool.core.lang.copier.Copier;
import aiyh.utils.tool.cn.hutool.core.util.ObjectUtil;
/**
*
*
* @param <S>
* @param <T>
* @author looly
* @since 5.8.0
*/
public abstract class AbsCopier<S, T> implements Copier<T> {
protected final S source;
protected final T target;
/**
*
*/
protected final CopyOptions copyOptions;
public AbsCopier(S source, T target, CopyOptions copyOptions) {
this.source = source;
this.target = target;
this.copyOptions = ObjectUtil.defaultIfNull(copyOptions, CopyOptions::create);
}
}

View File

@ -0,0 +1,94 @@
package aiyh.utils.tool.cn.hutool.core.bean.copier;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.lang.copier.Copier;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.Map;
/**
* Bean
*
* <pre>
* 1. Bean Bean
* 2. Bean Map
* 3. Map Bean
* 4. Map Map
* </pre>
*
* @author looly
*
* @param <T>
* @since 3.2.3
*/
public class BeanCopier<T> implements Copier<T>, Serializable {
private static final long serialVersionUID = 1L;
private final Copier<T> copier;
/**
* BeanCopier
*
* @param <T> Bean
* @param source BeanMap
* @param target Bean
* @param copyOptions
* @return BeanCopier
*/
public static <T> BeanCopier<T> create(Object source, T target, CopyOptions copyOptions) {
return create(source, target, target.getClass(), copyOptions);
}
/**
* BeanCopier
*
* @param <T> Bean
* @param source BeanMap
* @param target Bean
* @param destType Bean
* @param copyOptions
* @return BeanCopier
*/
public static <T> BeanCopier<T> create(Object source, T target, Type destType, CopyOptions copyOptions) {
return new BeanCopier<>(source, target, destType, copyOptions);
}
/**
*
*
* @param source BeanMap
* @param target Bean
* @param targetType Bean
* @param copyOptions
*/
public BeanCopier(Object source, T target, Type targetType, CopyOptions copyOptions) {
Assert.notNull(source, "Source bean must be not null!");
Assert.notNull(target, "Target bean must be not null!");
Copier<T> copier;
if (source instanceof Map) {
if (target instanceof Map) {
//noinspection unchecked
copier = (Copier<T>) new MapToMapCopier((Map<?, ?>) source, (Map<?, ?>) target, targetType, copyOptions);
} else {
copier = new MapToBeanCopier<>((Map<?, ?>) source, target, targetType, copyOptions);
}
}else if(source instanceof ValueProvider){
//noinspection unchecked
copier = new ValueProviderToBeanCopier<>((ValueProvider<String>) source, target, targetType, copyOptions);
} else {
if (target instanceof Map) {
//noinspection unchecked
copier = (Copier<T>) new BeanToMapCopier(source, (Map<?, ?>) target, targetType, copyOptions);
} else {
copier = new BeanToBeanCopier<>(source, target, targetType, copyOptions);
}
}
this.copier = copier;
}
@Override
public T copy() {
return copier.copy();
}
}

View File

@ -0,0 +1,91 @@
package aiyh.utils.tool.cn.hutool.core.bean.copier;
import aiyh.utils.tool.cn.hutool.core.bean.BeanUtil;
import aiyh.utils.tool.cn.hutool.core.bean.PropDesc;
import aiyh.utils.tool.cn.hutool.core.lang.Assert;
import aiyh.utils.tool.cn.hutool.core.util.TypeUtil;
import java.lang.reflect.Type;
import java.util.Map;
/**
* BeanBean
*
* @param <S> Bean
* @param <T> Bean
* @since 5.8.0
*/
public class BeanToBeanCopier<S, T> extends AbsCopier<S, T> {
/**
*
*/
private final Type targetType;
/**
*
*
* @param source Map
* @param target Bean
* @param targetType
* @param copyOptions
*/
public BeanToBeanCopier(S source, T target, Type targetType, CopyOptions copyOptions) {
super(source, target, copyOptions);
this.targetType = targetType;
}
@Override
public T copy() {
Class<?> actualEditable = target.getClass();
if (null != copyOptions.editable) {
// 检查限制类是否为target的父类或接口
Assert.isTrue(copyOptions.editable.isInstance(target),
"Target class [{}] not assignable to Editable class [{}]", actualEditable.getName(), copyOptions.editable.getName());
actualEditable = copyOptions.editable;
}
final Map<String, PropDesc> targetPropDescMap = BeanUtil.getBeanDesc(actualEditable).getPropMap(copyOptions.ignoreCase);
final Map<String, PropDesc> sourcePropDescMap = BeanUtil.getBeanDesc(source.getClass()).getPropMap(copyOptions.ignoreCase);
sourcePropDescMap.forEach((sFieldName, sDesc) -> {
if (null == sFieldName || false == sDesc.isReadable(copyOptions.transientSupport)) {
// 字段空或不可读,跳过
return;
}
sFieldName = copyOptions.editFieldName(sFieldName);
// 对key做转换转换后为null的跳过
if (null == sFieldName) {
return;
}
// 忽略不需要拷贝的 key,
if (false == copyOptions.testKeyFilter(sFieldName)) {
return;
}
// 检查目标字段可写性
final PropDesc tDesc = targetPropDescMap.get(sFieldName);
if (null == tDesc || false == tDesc.isWritable(this.copyOptions.transientSupport)) {
// 字段不可写,跳过之
return;
}
// 检查源对象属性是否过滤属性
Object sValue = sDesc.getValue(this.source);
if (false == copyOptions.testPropertyFilter(sDesc.getField(), sValue)) {
return;
}
// 获取目标字段真实类型并转换源值
final Type fieldType = TypeUtil.getActualType(this.targetType, tDesc.getFieldType());
//sValue = Convert.convertWithCheck(fieldType, sValue, null, this.copyOptions.ignoreError);
sValue = this.copyOptions.convertField(fieldType, sValue);
sValue = copyOptions.editFieldValue(sFieldName, sValue);
// 目标赋值
tDesc.setValue(this.target, sValue, copyOptions.ignoreNullValue, copyOptions.ignoreError, copyOptions.override);
});
return this.target;
}
}

Some files were not shown because too many files have changed in this diff Show More