From c1a17a8bf1c44577263685ce13942c518791bf4f Mon Sep 17 00:00:00 2001 From: jExpress - Hello Summer! Date: Mon, 4 Dec 2023 10:45:18 -0500 Subject: [PATCH] Release 2.3.12 (#267) * enabled customized delimiter of collection in @Config with new collectionDelimiter field * refactoring * refactoring hit-> txId * refactoring * refactoring * dependency update * release 2.3.12 --- pom.xml | 30 ++++---- .../jexpress/boot/BootConstant.java | 2 +- .../jexpress/boot/SummerBigBang.java | 2 +- .../jexpress/boot/SummerSingularity.java | 6 +- .../jexpress/boot/config/BootConfig.java | 3 +- .../boot/config/annotation/Config.java | 2 + .../nio/server/BootHttpExceptionHandler.java | 7 +- .../jexpress/nio/server/NioHttpUtil.java | 2 +- .../server/NioServerHttpRequestHandler.java | 23 +++--- .../nio/server/domain/ServiceContext.java | 22 ++++-- .../server/ws/rs/JaxRsRequestParameter.java | 3 +- .../jexpress/util/FormatterUtil.java | 75 ++++++++++--------- .../jexpress/util/ReflectionUtil.java | 15 ++-- 13 files changed, 104 insertions(+), 88 deletions(-) diff --git a/pom.xml b/pom.xml index 0325e8c9..b2f496a2 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.summerboot jexpress - 2.3.11 + 2.3.12 jar Summer Boot jExpress Summer Boot jExpress focuses on solving non-functional and operational maintainability requirements, some of which Spring Boot has (may) not yet provided @@ -172,30 +172,30 @@ 11 11 - 3.13.0 + 3.14.0 1.6.0 - 2.15.0 + 2.15.1 - 2.21.1 + 2.22.0 3.4.4 2.0.1 - 1.76 + 1.77 0.11.5 - 4.1.100.Final + 4.1.101.Final 2.0.62.Final - 1.59.0 + 1.59.1 32.1.3-jre - 3.24.4 + 3.25.1 - 2.2.18 + 2.2.19 @@ -207,22 +207,22 @@ 0.10.2 - 2.15.3 + 2.16.0 8.0.1.Final 4.0.2 - 5.1.0 + 7.0.0 - 6.3.1.Final - 5.0.1 + 6.4.0.Final + 5.1.0 - 5.0.2 + 5.1.0 - 2.3.2 + 2.5.0-rc1 2.3.32 diff --git a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java index 42f395ce..c20cc925 100644 --- a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java +++ b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java @@ -26,7 +26,7 @@ public interface BootConstant { String APP_ID = String.format("%06d", new Random().nextInt(999999)); //version - String VERSION = "SummerBoot.jExpress 2.3.11"; + String VERSION = "SummerBoot.jExpress 2.3.12"; String JEXPRESS_PACKAGE_NAME = "org.summerboot.jexpress"; String DEFAULT_ADMIN_MM = "changeit"; diff --git a/src/main/java/org/summerboot/jexpress/boot/SummerBigBang.java b/src/main/java/org/summerboot/jexpress/boot/SummerBigBang.java index c318af57..1f1e40f0 100644 --- a/src/main/java/org/summerboot/jexpress/boot/SummerBigBang.java +++ b/src/main/java/org/summerboot/jexpress/boot/SummerBigBang.java @@ -588,7 +588,7 @@ protected int scanAnnotation_Scheduled(Injector injector, String... rootPackageN for (Class c : classes) { try { triggers += QuartzUtil.addQuartzJob(scheduler, c); - } catch (SchedulerException ex) { + } catch (Throwable ex) { throw new RuntimeException("Filed to addQuartzJob for " + c, ex); } } diff --git a/src/main/java/org/summerboot/jexpress/boot/SummerSingularity.java b/src/main/java/org/summerboot/jexpress/boot/SummerSingularity.java index 449b5dd9..12166556 100644 --- a/src/main/java/org/summerboot/jexpress/boot/SummerSingularity.java +++ b/src/main/java/org/summerboot/jexpress/boot/SummerSingularity.java @@ -36,7 +36,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Random; import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; @@ -301,11 +300,8 @@ protected void scanArgsToInitializeLogging(String[] args) { System.exit(1); } //set log folder outside user specified config folder - Random rnd = new Random(); - int number = rnd.nextInt(999999); - String logId = String.format("%06d", number); // this will convert any number sequence into 6 character. - System.setProperty(BootConstant.SYS_PROP_LOGID, logId); + System.setProperty(BootConstant.SYS_PROP_LOGID, BootConstant.APP_ID); System.setProperty(BootConstant.SYS_PROP_LOGFILEPATH, userSpecifiedConfigDir.getParent() + File.separator + BootConstant.DIR_LOG);//used by log4j2.xml pluginDir = new File(userSpecifiedConfigDir.getParentFile(), BootConstant.DIR_PLUGIN).getAbsoluteFile(); // } diff --git a/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java b/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java index 96a3c6f2..7f5b8310 100644 --- a/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java +++ b/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java @@ -323,7 +323,8 @@ protected void loadField(Field field, String configFolder, ConfigUtil helper, Pr valueInCfgFile = configFolder + File.separator + valueInCfgFile; } } - ReflectionUtil.loadField(this, field, valueInCfgFile, autoDecrypt, isEmailRecipients); + String collectionDelimiter = cfgAnnotation.collectionDelimiter(); + ReflectionUtil.loadField(this, field, valueInCfgFile, autoDecrypt, isEmailRecipients, collectionDelimiter); } } diff --git a/src/main/java/org/summerboot/jexpress/boot/config/annotation/Config.java b/src/main/java/org/summerboot/jexpress/boot/config/annotation/Config.java index 7ed52962..b4c2edd1 100644 --- a/src/main/java/org/summerboot/jexpress/boot/config/annotation/Config.java +++ b/src/main/java/org/summerboot/jexpress/boot/config/annotation/Config.java @@ -59,5 +59,7 @@ public enum Validate { * @return */ String callbackMethodName4Dump() default ""; + + String collectionDelimiter() default ","; } diff --git a/src/main/java/org/summerboot/jexpress/nio/server/BootHttpExceptionHandler.java b/src/main/java/org/summerboot/jexpress/nio/server/BootHttpExceptionHandler.java index ccd9860c..e2840f69 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/BootHttpExceptionHandler.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/BootHttpExceptionHandler.java @@ -22,6 +22,7 @@ import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpResponseStatus; import jakarta.persistence.PersistenceException; +import java.io.IOException; import java.net.http.HttpConnectTimeoutException; import java.net.http.HttpTimeoutException; import java.util.Collection; @@ -69,7 +70,7 @@ public void onNamingException(NamingException ex, HttpMethod httptMethod, String if (cause == null) { cause = ex; } - if (cause instanceof java.net.UnknownHostException) { + if (cause instanceof IOException) {// java.net.UnknownHostException HealthMonitor.setHealthStatus(false, ex.toString(), healthInspector); nakFatal(context, HttpResponseStatus.SERVICE_UNAVAILABLE, BootErrorCode.ACCESS_ERROR_LDAP, "LDAP " + cause.getClass().getSimpleName(), ex, cmtpCfg.getEmailToAppSupport(), httptMethod + " " + httpRequestPath); } else { @@ -85,7 +86,7 @@ public void onPersistenceException(PersistenceException ex, HttpMethod httptMeth if (cause == null) { cause = ex; } - if (cause instanceof java.net.ConnectException) { + if (cause instanceof IOException) {// java.net.ConnectException HealthMonitor.setHealthStatus(false, ex.toString(), healthInspector); nakFatal(context, HttpResponseStatus.SERVICE_UNAVAILABLE, BootErrorCode.ACCESS_ERROR_DATABASE, "DB " + cause.getClass().getSimpleName(), ex, cmtpCfg.getEmailToAppSupport(), httptMethod + " " + httpRequestPath); } else { @@ -152,7 +153,7 @@ protected void nakFatal(ServiceContext context, HttpResponseStatus httpResponseS // 2. send sendAlertAsync if (po != null) { // build email content - String briefContent = "caller=" + context.callerId() + ", request#" + context.hit() + ": " + content; + String briefContent = "caller=" + context.callerId() + ", request#" + context.txId() + ": " + content; po.sendAlertAsync(emailTo, errorMessage, briefContent, ex, true); } } diff --git a/src/main/java/org/summerboot/jexpress/nio/server/NioHttpUtil.java b/src/main/java/org/summerboot/jexpress/nio/server/NioHttpUtil.java index 80b6db98..5c7ea902 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/NioHttpUtil.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/NioHttpUtil.java @@ -120,7 +120,7 @@ public static long sendResponse(ChannelHandlerContext ctx, boolean isKeepAlive, if (processorSettings != null) { String key = processorSettings.getHttpServiceResponseHeaderName_Reference(); if (key != null) { - serviceContext.responseHeader(key, serviceContext.hit()); + serviceContext.responseHeader(key, serviceContext.txId()); } key = processorSettings.getHttpServiceResponseHeaderName_ServerTimestamp(); if (key != null) { diff --git a/src/main/java/org/summerboot/jexpress/nio/server/NioServerHttpRequestHandler.java b/src/main/java/org/summerboot/jexpress/nio/server/NioServerHttpRequestHandler.java index e253b8c5..8f802660 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/NioServerHttpRequestHandler.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/NioServerHttpRequestHandler.java @@ -112,6 +112,7 @@ public void channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest } NioCounter.COUNTER_HIT.incrementAndGet(); final long hitIndex = NioCounter.COUNTER_BIZ_HIT.incrementAndGet(); + final String txId = BootConstant.APP_ID + "-" + hitIndex; // if (HttpUtil.is100ContinueExpected(req)) { // ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE, Unpooled.EMPTY_BUFFER)); // } @@ -126,7 +127,7 @@ public void channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest final String httpRequestUri = req.uri(); final boolean isKeepAlive = HttpUtil.isKeepAlive(req); - final String requestMetaInfo = requestMetaInfo(ctx, hitIndex, httpMethod, httpRequestUri, isKeepAlive, dataSize); + final String requestMetaInfo = requestMetaInfo(ctx, txId, httpMethod, httpRequestUri, isKeepAlive, dataSize); log.debug(() -> requestMetaInfo); final HttpHeaders requestHeaders = req.headers(); @@ -140,7 +141,7 @@ public void channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest final QueryStringDecoder queryStringDecoder = new QueryStringDecoder(httpRequestUri, StandardCharsets.UTF_8); Runnable asyncTask = () -> { long queuingTime = System.currentTimeMillis() - start; - ServiceContext context = ServiceContext.build(ctx, hitIndex, start, requestHeaders, httpMethod, httpRequestUri, httpPostRequestBody).responseHeaders(nioCfg.getServerDefaultResponseHeaders()).clientAcceptContentType(requestHeaders.get(HttpHeaderNames.ACCEPT)); + ServiceContext context = ServiceContext.build(ctx, txId, hitIndex, start, requestHeaders, httpMethod, httpRequestUri, httpPostRequestBody).responseHeaders(nioCfg.getServerDefaultResponseHeaders()).clientAcceptContentType(requestHeaders.get(HttpHeaderNames.ACCEPT)); String acceptCharset = requestHeaders.get(HttpHeaderNames.ACCEPT_CHARSET); if (StringUtils.isNotBlank(acceptCharset)) { context.charsetName(acceptCharset);//.contentType(ServiceContext.CONTENT_TYPE_JSON_ + acceptCharset); do not build content type with charset now, don't know charset valid or not @@ -185,9 +186,9 @@ public void channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest //response#1=200 OK, error=0, r2q=7ms, r2r=60ms, caller=aaa#bbb, received#1=GET /a StringBuilder sb = new StringBuilder(); //line1 - sb.append("request_").append(hitIndex).append(".caller=").append(caller == null ? context.callerId() : caller); + sb.append("request_").append(txId).append(".caller=").append(caller == null ? context.callerId() : caller); //line2,3 - sb.append("\n\t").append(requestMetaInfo).append("\n\tresponse_").append(hitIndex).append("=").append(status) + sb.append("\n\t").append(requestMetaInfo).append("\n\tresponse_").append(txId).append("=").append(status) .append(", error=").append(errorCount) .append(", FullHttpRequest.t0=").append(TimeUtil.toOffsetDateTime(start, zoneId)) .append(", queuing=").append(queuingTime).append("ms, process=").append(processTime); @@ -247,14 +248,14 @@ public void channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest nioCfg.getBizExecutor().execute(asyncTask); } catch (RejectedExecutionException ex) { long queuingTime = System.currentTimeMillis() - start; - ServiceContext context = ServiceContext.build(ctx, hitIndex, start, requestHeaders, httpMethod, httpRequestUri, httpPostRequestBody).responseHeaders(nioCfg.getServerDefaultResponseHeaders()).clientAcceptContentType(requestHeaders.get(HttpHeaderNames.ACCEPT)); + ServiceContext context = ServiceContext.build(ctx, txId, hitIndex, start, requestHeaders, httpMethod, httpRequestUri, httpPostRequestBody).responseHeaders(nioCfg.getServerDefaultResponseHeaders()).clientAcceptContentType(requestHeaders.get(HttpHeaderNames.ACCEPT)); Err e = new Err(BootErrorCode.NIO_TOO_MANY_REQUESTS, null, null, ex, "Too many request, try again later"); context.error(e).status(HttpResponseStatus.TOO_MANY_REQUESTS).level(Level.FATAL); long responseContentLength = NioHttpUtil.sendResponse(ctx, isKeepAlive, context, this, null); StringBuilder sb = new StringBuilder(); - sb.append("request_").append(hitIndex).append("=").append(ex.toString()) - .append("ms\n\t").append(requestMetaInfo).append("\n\tresponse#").append(hitIndex) + sb.append("request_").append(txId).append("=").append(ex.toString()) + .append("ms\n\t").append(requestMetaInfo).append("\n\tresponse#").append(txId) .append("=").append(context.status()) .append(", errorCode=").append(e.getErrorCode()) .append(", queuing=").append(queuingTime) @@ -264,13 +265,13 @@ public void channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest log.fatal(sb.toString()); } catch (Throwable ex) { long queuingTime = System.currentTimeMillis() - start; - ServiceContext context = ServiceContext.build(ctx, hitIndex, start, requestHeaders, httpMethod, httpRequestUri, httpPostRequestBody).responseHeaders(nioCfg.getServerDefaultResponseHeaders()).clientAcceptContentType(requestHeaders.get(HttpHeaderNames.ACCEPT)); + ServiceContext context = ServiceContext.build(ctx, txId, hitIndex, start, requestHeaders, httpMethod, httpRequestUri, httpPostRequestBody).responseHeaders(nioCfg.getServerDefaultResponseHeaders()).clientAcceptContentType(requestHeaders.get(HttpHeaderNames.ACCEPT)); Err e = new Err(BootErrorCode.NIO_UNEXPECTED_EXECUTOR_FAILURE, null, null, ex, "NIO unexpected executor failure"); context.error(e).status(HttpResponseStatus.INTERNAL_SERVER_ERROR).level(Level.FATAL); long responseContentLength = NioHttpUtil.sendResponse(ctx, isKeepAlive, context, this, null); StringBuilder sb = new StringBuilder(); - sb.append("request_").append(hitIndex).append("=").append(ex.toString()) - .append("ms\n\t").append(requestMetaInfo).append("\n\tresponse#").append(hitIndex) + sb.append("request_").append(txId).append("=").append(ex.toString()) + .append("ms\n\t").append(requestMetaInfo).append("\n\tresponse#").append(txId) .append("=").append(context.status()) .append(", errorCode=").append(e.getErrorCode()) .append(", queuing=").append(queuingTime) @@ -291,7 +292,7 @@ private String info(ChannelHandlerContext ctx) { .toString(); } - private String requestMetaInfo(ChannelHandlerContext ctx, long hitIndex, HttpMethod httpMethod, String httpRequestUri, boolean isKeepAlive, long dataSize) { + private String requestMetaInfo(ChannelHandlerContext ctx, String hitIndex, HttpMethod httpMethod, String httpRequestUri, boolean isKeepAlive, long dataSize) { return new StringBuilder() .append("request_").append(hitIndex) .append("=").append(httpMethod).append(" ").append(httpRequestUri) diff --git a/src/main/java/org/summerboot/jexpress/nio/server/domain/ServiceContext.java b/src/main/java/org/summerboot/jexpress/nio/server/domain/ServiceContext.java index add63ff8..8e7b8e13 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/domain/ServiceContext.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/domain/ServiceContext.java @@ -68,6 +68,7 @@ public class ServiceContext { private final String requesURI; private final HttpHeaders requestHeaders; private final String requestBody; + private final String txId; private final long hit; private final long startTs; private Caller caller; @@ -107,11 +108,15 @@ public class ServiceContext { private boolean logResponseBody = true; public static ServiceContext build(long hit) { - return new ServiceContext(null, hit, System.currentTimeMillis(), null, null, null, null); + return build(BootConstant.APP_ID + "-" + hit, hit); } - public static ServiceContext build(ChannelHandlerContext ctx, long hit, long startTs, HttpHeaders requestHeaders, HttpMethod requesMethod, String requesURI, String requestBody) { - return new ServiceContext(ctx, hit, startTs, requestHeaders, requesMethod, requesURI, requestBody); + public static ServiceContext build(String txId, long hit) { + return new ServiceContext(null, txId, hit, System.currentTimeMillis(), null, null, null, null); + } + + public static ServiceContext build(ChannelHandlerContext ctx, String txId, long hit, long startTs, HttpHeaders requestHeaders, HttpMethod requesMethod, String requesURI, String requestBody) { + return new ServiceContext(ctx, txId, hit, startTs, requestHeaders, requesMethod, requesURI, requestBody); } @Override @@ -120,7 +125,7 @@ public String toString() { return "ServiceContext{" + "status=" + status + ", responseHeaders=" + responseHeaders + ", contentType=" + contentType + ", data=" + data + ", txt=" + txt + ", errors=" + serviceError + ", level=" + level + ", logReqHeader=" + logRequestHeader + ", logRespHeader=" + logResponseHeader + ", logReqContent=" + logRequestBody + ", logRespContent=" + logResponseBody + '}'; } - private ServiceContext(ChannelHandlerContext ctx, long hit, long startTs, HttpHeaders requestHeaders, HttpMethod requesMethod, String requesURI, String requestBody) { + private ServiceContext(ChannelHandlerContext ctx, String txId, long hit, long startTs, HttpHeaders requestHeaders, HttpMethod requesMethod, String requesURI, String requestBody) { if (ctx != null && ctx.channel() != null) { this.localIP = ctx.channel().localAddress(); this.remoteIP = ctx.channel().remoteAddress(); @@ -128,6 +133,7 @@ private ServiceContext(ChannelHandlerContext ctx, long hit, long startTs, HttpHe this.localIP = null; this.remoteIP = null; } + this.txId = txId; this.hit = hit; this.startTs = startTs; this.requestHeaders = requestHeaders; @@ -220,6 +226,10 @@ public ServiceContext reset() { } //@JsonInclude(JsonInclude.Include.NON_NULL) + public String txId() { + return txId; + } + public long hit() { return hit; } @@ -661,7 +671,7 @@ public ServiceError error() { */ public ServiceContext error(Err error) { if (serviceError == null) { - serviceError = new ServiceError(BootConstant.APP_ID + "-" + hit); + serviceError = new ServiceError(txId); } if (error == null) { return this; @@ -693,7 +703,7 @@ public ServiceContext errors(Collection es) { return this; } if (serviceError == null) { - serviceError = new ServiceError(BootConstant.APP_ID + "-" + hit); + serviceError = new ServiceError(txId); } serviceError.addErrors(es); for (Err e : es) { diff --git a/src/main/java/org/summerboot/jexpress/nio/server/ws/rs/JaxRsRequestParameter.java b/src/main/java/org/summerboot/jexpress/nio/server/ws/rs/JaxRsRequestParameter.java index 0d194fce..75f33ba9 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/ws/rs/JaxRsRequestParameter.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/ws/rs/JaxRsRequestParameter.java @@ -68,6 +68,7 @@ public enum ParamType { private boolean autoBeanValidation = false; private boolean cookieParamObj = false; private final EnumConvert.To enumConvert; + private final String collectionDelimiter = null;// TODO public JaxRsRequestParameter(String info, HttpMethod httpMethod, List consumes, Parameter param) { String error = "\n\tparameter is not allowed in " + info + "(" + param + ")\n\t - "; @@ -374,7 +375,7 @@ private Object parse(String value, String defaultValue, ServiceContext context) } } try { - return ReflectionUtil.toJavaType(targetClass, parameterizedType, value, false, false, enumConvert); + return ReflectionUtil.toJavaType(targetClass, parameterizedType, value, false, false, enumConvert, collectionDelimiter); } catch (Throwable ex) { Err e = new Err(BootErrorCode.BAD_RQUEST_DATA, null, null, ex, "Failed to parse data type: invalid " + type + "{" + key + "}=" + value); context.status(HttpResponseStatus.BAD_REQUEST).error(e); diff --git a/src/main/java/org/summerboot/jexpress/util/FormatterUtil.java b/src/main/java/org/summerboot/jexpress/util/FormatterUtil.java index 6a993033..733a4f50 100644 --- a/src/main/java/org/summerboot/jexpress/util/FormatterUtil.java +++ b/src/main/java/org/summerboot/jexpress/util/FormatterUtil.java @@ -45,50 +45,53 @@ * @author Changski Tie Zheng Zhang 张铁铮, 魏泽北, 杜旺财, 杜富贵 */ public class FormatterUtil { - + protected static Logger log = null;// = LogManager.getLogger(FormatterUtil.class); public static final long INT_MASK = 0xFFFFFFFFL;//(long) Integer.MAX_VALUE - (long) Integer.MIN_VALUE; public static final int SHORT_MASK = 0xFFFF; public static final short BYTE_MASK = 0xFF; public static final short NIBBLE_MASK = 0x0F; - + public static final String[] EMPTY_STR_ARRAY = {}; public static final String REGEX_CSV = "\\s*,\\s*"; public static final String REGEX_URL = "\\s*/\\s*"; public static final String REGEX_BINDING_MAP = "\\s*:\\s*"; public static final String REGEX_EMAIL = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$"; public static final Pattern REGEX_EMAIL_PATTERN = Pattern.compile(REGEX_EMAIL); - + public static String[] parseDsv(String csv, String delimiter) { + if (StringUtils.isBlank(delimiter) || ",".equals(delimiter)) { + return parseCsv(csv); + } return StringUtils.isBlank(csv) ? EMPTY_STR_ARRAY : csv.trim().split("\\s*" + delimiter + "\\s*"); } - + public static String[] parseCsv(String csv) { return StringUtils.isBlank(csv) ? EMPTY_STR_ARRAY : csv.trim().split(REGEX_CSV); } - + public static String[] parseURL(String url) { return StringUtils.isBlank(url) ? EMPTY_STR_ARRAY : url.trim().split(REGEX_URL); } - + public static String[] parseURL(String url, boolean trim) { return StringUtils.isBlank(url) ? EMPTY_STR_ARRAY : trim ? url.trim().split(REGEX_URL) : url.split(REGEX_URL); } - + public static String toCSV(Collection a) { return a.stream().map(String::valueOf).collect(Collectors.joining(", ")); } - + public static String[] getEnumNames(Class> e) { //return Arrays.stream(MyEnum.values()).map(MyEnum::name).toArray(String[]::new); return Arrays.stream(e.getEnumConstants()).map(Enum::name).toArray(String[]::new); } - + public static Pattern INSIDE_PARENTHESES_VALUE = Pattern.compile("\\(([^)]+)\\)"); - + public static String getInsideParenthesesValue(String value) { String ret = value; // Matcher m = INSIDE_PARENTHESES_VALUE.matcher(value); @@ -102,13 +105,13 @@ public static String getInsideParenthesesValue(String value) { } return ret; } - + public static final String REGEX_FIRST_AND_LAST_B = "\\(.*\\)"; - + public static final Pattern REGEX_DEC_PATTERN = Pattern.compile(DECRYPTED_WARPER_PREFIX + REGEX_FIRST_AND_LAST_B); - + public static final Pattern REGEX_ENC_PATTERN = Pattern.compile(ENCRYPTED_WARPER_PREFIX + REGEX_FIRST_AND_LAST_B); - + public static String updateProtectedLine(String line, boolean encrypt) throws GeneralSecurityException { Matcher matcher = encrypt ? REGEX_DEC_PATTERN.matcher(line) @@ -126,7 +129,7 @@ public static String updateProtectedLine(String line, boolean encrypt) throws Ge } return null; } - + @Deprecated public static String updateProtectedLine_(String line, boolean encrypt) throws GeneralSecurityException { String ret = null; @@ -145,7 +148,7 @@ public static String updateProtectedLine_(String line, boolean encrypt) throws G } return ret; } - + public static String b2n(String s) { return StringUtils.isBlank(s) ? null : s.trim(); } @@ -163,7 +166,7 @@ public static Map parseBindingAddresss(String bindAddresses) { } return ret; } - + public static Map parseMap(String mapCVS) { //int[] ports = Arrays.stream(portsStr).mapToInt(Integer::parseInt).toArray(); Map ret = new HashMap<>(); @@ -174,24 +177,24 @@ public static Map parseMap(String mapCVS) { } return ret; } - + public static String convertTo(String value, String targetCharsetName) throws UnsupportedEncodingException { //String rawString = "Fantasticèéçà Entwickeln Sie mit Vergnügen"; return new String(value.getBytes(targetCharsetName), targetCharsetName); } - + public static String base64MimeEncode(byte[] contentBytes) { return Base64.getMimeEncoder().encodeToString(contentBytes); } - + public static byte[] base64MimeDecode(String encodedMime) { return Base64.getMimeDecoder().decode(encodedMime); } - + public static String base64Encode(byte[] contentBytes) { return Base64.getEncoder().encodeToString(contentBytes); } - + public static byte[] base64Decode(String encodedMime) { return Base64.getDecoder().decode(encodedMime); } @@ -210,11 +213,11 @@ public static byte[] toByteArray(BufferedImage bi, String format) throws IOExcep return bytes; } } - + public static String toString(ByteBuffer buffer) { return toString(buffer, true, true, 8, " "); } - + public static String toString(ByteBuffer buffer, boolean showStatus, boolean showHeaderfooter, int showNumberOfBytesPerLine, String delimiter) { StringBuilder sb = new StringBuilder(); if (showStatus) { @@ -268,11 +271,11 @@ public static byte[] parseHex(String hexString) { } return data; } - + public static Set findDuplicates(List listContainingDuplicates) { final Set setToReturn = new HashSet<>(); final Set set1 = new HashSet<>(); - + for (T yourInt : listContainingDuplicates) { if (!set1.add(yourInt)) { setToReturn.add(yourInt); @@ -280,7 +283,7 @@ public static Set findDuplicates(List listContainingDup } return setToReturn; } - + public static String protectContentNumber(String plain, String keyword, String delimiter, String replaceWith) { if (StringUtils.isBlank(plain)) { return plain; @@ -289,7 +292,7 @@ public static String protectContentNumber(String plain, String keyword, String d String replacement = keyword + delimiter + replaceWith; return plain.replaceAll(regex, replacement); } - + public static String protectContent(String plain, String keyword, String delimiter, String wrapper, String replaceWith) { if (StringUtils.isBlank(plain)) { return plain; @@ -305,42 +308,42 @@ public static String protectContent(String plain, String keyword, String delimit log.trace(() -> "replace " + plain + "\n\t regex=" + regex + "\n\t with=" + replacement); return plain.replaceAll(regex, replacement); } - + public static String protectJsonString(String json, String key, String replaceWith) { final String regex = "(\"" + key + "\"\\s*:\\s*\")[^\"]*(\")";//("key"\s*:\s*")[^"]*(") return json.replaceAll(regex, "$1" + replaceWith + "$2"); } - + public static String protectJsonString_InString(String json, String key, String replaceWith) { final String regex = "(\"" + key + "\\\\\"\\s*:\\s*\\\\\")[^\"]*(\")"; return json.replaceAll(regex, "$1" + replaceWith + "$2"); } - + public static String protectJsonNumber(String json, String key, String replaceWith) { String regex = "(\"" + key + "\"\\s*:\\s*)(\\d+)"; return json.replaceAll(regex, "$1" + replaceWith); } - + public static String protectJsonNumber_InString(String json, String key, String replaceWith) { String regex = "(\"" + key + "\\\\\"\\s*:\\s*)(\\d+)"; return json.replaceAll(regex, "$1" + replaceWith); } - + public static String protectJsonArray(String json, String key, String replaceWith) { final String regex = "(\"" + key + "\"\\s*:\\s*\\[)[^\\[]*(\\])"; return json.replaceAll(regex, "$1" + replaceWith + "$2"); } - + public static String[] splitByLength(String plain, int chunckSize) { return plain.split("(?<=\\G.{" + chunckSize + "})"); } - + public static T[] arrayCopy(T[] array1, T[] array2) { T[] result = Arrays.copyOf(array1, array1.length + array2.length); System.arraycopy(array2, 0, result, array1.length, array2.length); return result; } - + public static T[] arrayAdd(T[] array1, T newElement) { int size = array1.length; T[] result = Arrays.copyOf(array1, size + 1); diff --git a/src/main/java/org/summerboot/jexpress/util/ReflectionUtil.java b/src/main/java/org/summerboot/jexpress/util/ReflectionUtil.java index fd9960a2..edd856df 100644 --- a/src/main/java/org/summerboot/jexpress/util/ReflectionUtil.java +++ b/src/main/java/org/summerboot/jexpress/util/ReflectionUtil.java @@ -203,19 +203,20 @@ public static List getAllSuperClasses(Class targetClass) { * @param value * @param autoDecrypt * @param isEmailRecipients + * @param collectionDelimiter * @throws java.lang.IllegalAccessException */ - public static void loadField(Object instance, Field field, String value, final boolean autoDecrypt, final boolean isEmailRecipients) throws IllegalAccessException { + public static void loadField(Object instance, Field field, String value, final boolean autoDecrypt, final boolean isEmailRecipients, String collectionDelimiter) throws IllegalAccessException { Class targetClass = field.getType(); Type genericType = field.getGenericType(); field.setAccessible(true); - field.set(instance, toJavaType(targetClass, genericType, value, autoDecrypt, isEmailRecipients, null)); + field.set(instance, toJavaType(targetClass, genericType, value, autoDecrypt, isEmailRecipients, null, collectionDelimiter)); } private static final Type[] DEFAULT_ARG_TYPES = {String.class, String.class}; public static Object toJavaType(Class targetClass, Type genericType, String value, final boolean autoDecrypt, - final boolean isEmailRecipients, EnumConvert.To enumConvert) throws IllegalAccessException { + final boolean isEmailRecipients, EnumConvert.To enumConvert, String collectionDelimiter) throws IllegalAccessException { if (StringUtils.isBlank(value)) { Object nullValue = ReflectionUtil.toStandardJavaType(null, targetClass, autoDecrypt, false, enumConvert); return nullValue; @@ -246,7 +247,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu } if (targetClass.isArray()) { - String[] valuesStr = FormatterUtil.parseCsv(value); + String[] valuesStr = FormatterUtil.parseDsv(value, collectionDelimiter); if (valuesStr == null || valuesStr.length < 1) { return null; } @@ -257,7 +258,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu } return array; } else if (targetClass.equals(Set.class)) { - String[] valuesStr = FormatterUtil.parseCsv(value); + String[] valuesStr = FormatterUtil.parseDsv(value, collectionDelimiter); if (valuesStr == null || valuesStr.length < 1) { return null; } @@ -268,7 +269,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu } return Set.of((Object[]) array); } else if (targetClass.equals(SortedSet.class)) { - String[] valuesStr = FormatterUtil.parseCsv(value); + String[] valuesStr = FormatterUtil.parseDsv(value, collectionDelimiter); if (valuesStr == null || valuesStr.length < 1) { return null; } @@ -279,7 +280,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu } return ImmutableSortedSet.copyOf(List.of((Object[]) array)); } else if (targetClass.equals(List.class)) { - String[] valuesStr = FormatterUtil.parseCsv(value); + String[] valuesStr = FormatterUtil.parseDsv(value, collectionDelimiter); if (valuesStr == null || valuesStr.length < 1) { return null; }