diff --git a/pom.xml b/pom.xml
index c73bd45..2b5af1b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,9 +4,9 @@
4.0.0
org.summerboot
jexpress
- 2.5.0
+ 2.5.1
jar
- Summer Boot jExpress
+ Summer Boot jExpress ${version}
Summer Boot jExpress focuses on solving non-functional and operational maintainability requirements,
some of which Spring Boot has (may) not yet provided
@@ -182,7 +182,7 @@
21
- 3.4.0
+ 3.4.1
3.13.0
3.8.1
3.4.2
@@ -206,8 +206,8 @@
0.12.6
- 4.1.117.Final
- 2.0.69.Final
+ 4.1.119.Final
+ 2.0.70.Final
1.70.0
33.4.0-jre
@@ -218,7 +218,7 @@
- 3.0.0
+ 3.1.0
4.0.0
3.0.0
@@ -228,14 +228,14 @@
2.18.2
6.0.1
- 11.0.2
+ 11.0.4
8.0.2.Final
7.0.0
- 6.6.5.Final
+ 6.6.9.Final
6.2.1
@@ -254,11 +254,11 @@
1.0.10
1.18
- 9.0.0
- 6.0.0
+ 9.1.0
+ 6.1.0
- 7.10.2
+ 7.11.0
9.2.0
diff --git a/src/main/java/org/summerboot/jexpress/boot/BackOffice.java b/src/main/java/org/summerboot/jexpress/boot/BackOffice.java
index 0811d26..c8dd259 100644
--- a/src/main/java/org/summerboot/jexpress/boot/BackOffice.java
+++ b/src/main/java/org/summerboot/jexpress/boot/BackOffice.java
@@ -314,7 +314,7 @@ public Map getBootErrorCodeMapping() {
@Config(key = "naming.cli.psv", defaultValue = "psv")
private String cliName_psv = "psv";
- @Config(key = "naming.memo.delimiter", defaultValue = ": ")
+ @Config(key = "naming.memo.delimiter", defaultValue = ": ", trim = false)
private String memoDelimiter = ": ";
public Set getRootPackageNames() {
diff --git a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java
index 0f4d404..58a5ea9 100644
--- a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java
+++ b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java
@@ -17,17 +17,18 @@
import org.apache.logging.log4j.Level;
-import java.util.Random;
+import java.security.SecureRandom;
/**
* @author Changski Tie Zheng Zhang 张铁铮, 魏泽北, 杜旺财, 杜富贵
*/
public interface BootConstant {
- String APP_ID = String.format("%06d", new Random().nextInt(999999));
+ int APP_ID_VALUE = new SecureRandom().nextInt(999999);
+ String APP_ID = String.format("%06d", APP_ID_VALUE);
//version
- String VERSION = "jExpress 2.5.0";
+ String VERSION = "jExpress 2.5.1";
String JEXPRESS_PACKAGE_NAME = "org.summerboot.jexpress";
String DEFAULT_ADMIN_MM = "changeit";
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 f59eb5e..8691b82 100644
--- a/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java
+++ b/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java
@@ -274,7 +274,7 @@ protected void loadField(Field field, String configFolder, ConfigUtil helper, Pr
}
boolean isSpecifiedInCfgFile = props.containsKey(annotationKey);
if (isSpecifiedInCfgFile) {// 2. empty cfg value as null
- Object nullValue = ReflectionUtil.toStandardJavaType(null, field.getType(), false, false, null);
+ Object nullValue = ReflectionUtil.toStandardJavaType(null, false, field.getType(), false, false, null);
field.set(this, nullValue);
return;
} else {
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 22df4b1..891fae4 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
@@ -62,4 +62,6 @@ public enum Validate {
String collectionDelimiter() default ",";
+ boolean trim() default true;
+
}
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 d2517c1..48c7361 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
@@ -370,21 +370,21 @@ protected Object parse(String value, String defaultValue, ServiceContext context
Err e = new Err(BootErrorCode.BAD_REQUEST_MISSING_REQUIRED_FILED, null, null, null, "Missing Required Filed: " + type + "{" + key + "}=" + value);
context.status(HttpResponseStatus.BAD_REQUEST).error(e);
}
- return ReflectionUtil.toStandardJavaType(null, targetClass, false, false, null);//primitive types devault value or null
+ return ReflectionUtil.toStandardJavaType(null, false, targetClass, false, false, null);//primitive types devault value or null
}
}
String regex = pattern == null ? null : pattern.regexp();
if (regex != null && !value.matches(regex)) {
Err e = new Err(BootErrorCode.BAD_REQUEST_DATA, null, null, null, "Failed to parse data type: invalid " + type + "{" + key + "}=" + value + " by regex=" + regex);
context.status(HttpResponseStatus.BAD_REQUEST).error(e);
- return ReflectionUtil.toStandardJavaType(null, targetClass, false, false, null);//primitive types devault value or null
+ return ReflectionUtil.toStandardJavaType(null, false, targetClass, false, false, null);//primitive types devault value or null
}
try {
- return ReflectionUtil.toJavaType(targetClass, parameterizedType, value, false, false, enumConvert, collectionDelimiter);
+ return ReflectionUtil.toJavaType(targetClass, parameterizedType, value, true, false, false, enumConvert, collectionDelimiter);
} catch (Throwable ex) {
Err e = new Err(BootErrorCode.BAD_REQUEST_DATA, null, null, ex, "Failed to parse data type: invalid " + type + "{" + key + "}=" + value);
context.status(HttpResponseStatus.BAD_REQUEST).error(e);
- return ReflectionUtil.toStandardJavaType(null, targetClass, false, false, null);//primitive types devault value or null
+ return ReflectionUtil.toStandardJavaType(null, false, targetClass, false, false, null);//primitive types devault value or null
}
}
}
diff --git a/src/main/java/org/summerboot/jexpress/util/FormatterUtil.java b/src/main/java/org/summerboot/jexpress/util/FormatterUtil.java
index fcc24a1..6acef62 100644
--- a/src/main/java/org/summerboot/jexpress/util/FormatterUtil.java
+++ b/src/main/java/org/summerboot/jexpress/util/FormatterUtil.java
@@ -19,6 +19,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.summerboot.jexpress.boot.BootConstant;
import org.summerboot.jexpress.security.SecurityUtil;
import javax.imageio.ImageIO;
@@ -288,10 +289,24 @@ public static byte[] toByteArray(BufferedImage bi, String format) throws IOExcep
}
public static String toString(ByteBuffer buffer) {
- return toString(buffer, true, true, 8, " ");
+ return toString(buffer, true, true, 10, "\t");
}
- public static String toString(ByteBuffer buffer, boolean showStatus, boolean showHeaderfooter, int showNumberOfBytesPerLine, String delimiter) {
+ public static String toString(ByteBuffer buffer, boolean showStatus, boolean showHeaderfooter, int numberOfBytesPerLine) {
+ return toString(buffer, showStatus, showHeaderfooter, numberOfBytesPerLine, "\t");
+ }
+
+ public static String toString(ByteBuffer buffer, boolean showStatus, boolean showHeaderfooter, int numberOfBytesPerLine, String delimiter) {
+ return toString(buffer, showStatus, showHeaderfooter, numberOfBytesPerLine, delimiter, BootConstant.BR, "ByteBuffer Contents starts", "ByteBuffer Contents ends");
+ }
+
+ public static String toString(ByteBuffer buffer, boolean showStatus, boolean showHeaderfooter, int numberOfBytesPerLine, String delimiter, String br, String header, String footer) {
+ if (buffer == null) {
+ return "";
+ }
+ if (br == null) {
+ br = BootConstant.BR;
+ }
StringBuilder sb = new StringBuilder();
if (showStatus) {
sb.append("ByteBuffer status:")
@@ -299,28 +314,68 @@ public static String toString(ByteBuffer buffer, boolean showStatus, boolean sho
.append(" Position=").append(buffer.position())
.append(" Limit=").append(buffer.limit())
.append(" Capacity=").append(buffer.capacity())
- .append(" Remaining=").append(buffer.remaining());
+ .append(" Remaining=").append(buffer.remaining())
+ .append(br);
}
if (showHeaderfooter) {
- sb.append("\n************** ByteBuffer Contents starts **************\n");
+ buuldHeaderfooter(header, numberOfBytesPerLine, delimiter, sb, br);
}
boolean eol = false;
- if (showNumberOfBytesPerLine > 0) {
+ if (numberOfBytesPerLine > 0) {
byte[] array = buffer.array();
for (int i = 0; i < buffer.limit(); i++) {
- eol = (i + 1) % showNumberOfBytesPerLine == 0;
- sb.append(String.format("0x%02X", array[i])).append(eol ? "\n" : delimiter);
+ eol = (i + 1) % numberOfBytesPerLine == 0;
+ //String hexChars = String.format("0x%02X", array[i]);
+ // replaced String.format("0x%02X", i) with better performance api, 100 times faster via byte operations: 10k loads performace: 317ms vs 2ms
+ char[] hexChars = toString(array[i], true);
+ sb.append(hexChars).append(eol ? br : delimiter);
}
}
if (showHeaderfooter) {
if (!eol) {
sb.append("\n");
}
- sb.append("************** ByteBuffer Contents ends **************\n");
+ buuldHeaderfooter(footer, numberOfBytesPerLine, delimiter, sb, br);
}
return sb.toString();
}
+ public static final short HEX_STRING_SIZE = 4;
+ public static final char[] HexArrayIndexTable = "0123456789ABCDEF".toCharArray();
+
+ private static void buuldHeaderfooter(String title, int numberOfBytesPerLine, String delimiter, StringBuilder sb, String br) {
+ int delimiterSize = delimiter.equals("\t") ? 4 : delimiter.length();
+ int lineSize = HEX_STRING_SIZE * numberOfBytesPerLine + delimiterSize * (numberOfBytesPerLine - 1);
+ int titleSize = title.length() + 2;
+ int totalAsteriskSize = lineSize - titleSize;
+ int asteriskSize = Math.max(2, totalAsteriskSize / 2 + totalAsteriskSize % 2);
+ String asteriskLine = StringUtils.repeat("*", asteriskSize);
+ sb.append(asteriskLine).append(" ").append(title).append(" ").append(asteriskLine).append(br);
+ }
+
+ /**
+ * replaced String.format("0x%02X", i) with better performance api, 100 times faster via byte operations: 10k loads performace: 317ms vs 2ms
+ *
+ * @param v
+ * @return
+ */
+ public static char[] toString(byte v, boolean append0x) {
+ int b = v & 0xFF;
+ char[] hexChars;
+ if (append0x) {
+ hexChars = new char[4];
+ hexChars[0] = '0';
+ hexChars[1] = 'x';
+ hexChars[2] = HexArrayIndexTable[b >>> 4];
+ hexChars[3] = HexArrayIndexTable[b & 0x0F];
+ } else {
+ hexChars = new char[2];
+ hexChars[0] = HexArrayIndexTable[b >>> 4];
+ hexChars[1] = HexArrayIndexTable[b & 0x0F];
+ }
+ return hexChars;
+ }
+
/**
* For old Java before Java 17 HexFormat.of().parseHex(s)
*
diff --git a/src/main/java/org/summerboot/jexpress/util/ReflectionUtil.java b/src/main/java/org/summerboot/jexpress/util/ReflectionUtil.java
index c08038e..e3dd745 100644
--- a/src/main/java/org/summerboot/jexpress/util/ReflectionUtil.java
+++ b/src/main/java/org/summerboot/jexpress/util/ReflectionUtil.java
@@ -20,6 +20,7 @@
import com.google.common.collect.ImmutableSortedSet;
import org.apache.commons.lang3.StringUtils;
import org.reflections.Reflections;
+import org.summerboot.jexpress.boot.config.annotation.Config;
import org.summerboot.jexpress.nio.server.ws.rs.EnumConvert;
import org.summerboot.jexpress.security.SecurityUtil;
@@ -209,19 +210,23 @@ public static void loadField(Object instance, Field field, String value, final b
Class targetClass = field.getType();
Type genericType = field.getGenericType();
field.setAccessible(true);
- field.set(instance, toJavaType(targetClass, genericType, value, autoDecrypt, isEmailRecipients, null, collectionDelimiter));
+ Config cfgSettings = field.getAnnotation(Config.class);
+ boolean trim = cfgSettings == null ? false : cfgSettings.trim();
+ field.set(instance, toJavaType(targetClass, genericType, value, trim, autoDecrypt, isEmailRecipients, null, collectionDelimiter));
}
protected static final Type[] DEFAULT_ARG_TYPES = {String.class, String.class};
- public static Object toJavaType(Class targetClass, Type genericType, String value, final boolean autoDecrypt,
+ public static Object toJavaType(Class targetClass, Type genericType, String value, final boolean trim, final boolean autoDecrypt,
final boolean isEmailRecipients, EnumConvert.To enumConvert, String collectionDelimiter) throws IllegalAccessException {
if (StringUtils.isBlank(value)) {
- Object nullValue = ReflectionUtil.toStandardJavaType(null, targetClass, autoDecrypt, false, enumConvert);
+ Object nullValue = ReflectionUtil.toStandardJavaType(null, trim, targetClass, autoDecrypt, false, enumConvert);
return nullValue;
}
- value = value.trim();
+ if (trim) {
+ value = value.trim();
+ }
// Class targetClass = field.getType();
// Type genericType = field.getGenericType();
Type[] argTypes = DEFAULT_ARG_TYPES;
@@ -253,7 +258,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
Class classT = targetClass.getComponentType();
Object array = Array.newInstance(classT, valuesStr.length);
for (int i = 0; i < valuesStr.length; i++) {
- Array.set(array, i, toStandardJavaType(valuesStr[i], classT, autoDecrypt, isEmailRecipients, enumConvert));
+ Array.set(array, i, toStandardJavaType(valuesStr[i], trim, classT, autoDecrypt, isEmailRecipients, enumConvert));
}
return array;
} else if (targetClass.equals(Set.class)) {
@@ -264,7 +269,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
Class classT = upperBoundClasses[0];//(Class) argTypes[0];
Object array = Array.newInstance(classT, valuesStr.length);
for (int i = 0; i < valuesStr.length; i++) {
- Array.set(array, i, toStandardJavaType(valuesStr[i], classT, autoDecrypt, isEmailRecipients, enumConvert));
+ Array.set(array, i, toStandardJavaType(valuesStr[i], trim, classT, autoDecrypt, isEmailRecipients, enumConvert));
}
return Set.of((Object[]) array);
} else if (targetClass.equals(SortedSet.class)) {
@@ -275,7 +280,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
Class classT = upperBoundClasses[0];//(Class) argTypes[0];
Object array = Array.newInstance(classT, valuesStr.length);
for (int i = 0; i < valuesStr.length; i++) {
- Array.set(array, i, toStandardJavaType(valuesStr[i], classT, autoDecrypt, isEmailRecipients, enumConvert));
+ Array.set(array, i, toStandardJavaType(valuesStr[i], trim, classT, autoDecrypt, isEmailRecipients, enumConvert));
}
return ImmutableSortedSet.copyOf(List.of((Object[]) array));
} else if (targetClass.equals(List.class)) {
@@ -286,7 +291,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
Class classT = upperBoundClasses[0];//(Class) argTypes[0];
Object array = Array.newInstance(classT, valuesStr.length);
for (int i = 0; i < valuesStr.length; i++) {
- Array.set(array, i, toStandardJavaType(valuesStr[i], classT, autoDecrypt, isEmailRecipients, enumConvert));
+ Array.set(array, i, toStandardJavaType(valuesStr[i], trim, classT, autoDecrypt, isEmailRecipients, enumConvert));
}
return List.of((Object[]) array);
} else if (targetClass.equals(Map.class)) {
@@ -299,8 +304,8 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
Map ret = new HashMap();
for (var k : stringMap.keySet()) {
String v = stringMap.get(k);
- Object keyT = toStandardJavaType(k, classT1, autoDecrypt, isEmailRecipients, enumConvert);
- Object valueT = toStandardJavaType(v, classT2, autoDecrypt, isEmailRecipients, enumConvert);
+ Object keyT = toStandardJavaType(k, trim, classT1, autoDecrypt, isEmailRecipients, enumConvert);
+ Object valueT = toStandardJavaType(v, trim, classT2, autoDecrypt, isEmailRecipients, enumConvert);
ret.put(keyT, valueT);
}
return Map.copyOf(ret);
@@ -321,7 +326,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
throw new IllegalArgumentException("invalid json data: " + value, ex);
}
} else {
- Object v = toStandardJavaType(value, targetClass, autoDecrypt, isEmailRecipients, enumConvert);
+ Object v = toStandardJavaType(value, trim, targetClass, autoDecrypt, isEmailRecipients, enumConvert);
return v;
}
}
@@ -337,7 +342,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
* @param isEmailRecipients
* @return
*/
- public static Object toStandardJavaType(String value, final Class targetClass, final boolean autoDecrypt,
+ public static Object toStandardJavaType(String value, final boolean trim, final Class targetClass, final boolean autoDecrypt,
final boolean isEmailRecipients, EnumConvert.To enumConvert) {
if (StringUtils.isBlank(value)) {
if (targetClass.equals(boolean.class)) {
@@ -357,7 +362,9 @@ public static Object toStandardJavaType(String value, final Class targetClass, f
return null;
}
}
- value = value.trim();
+ if (trim) {
+ value = value.trim();
+ }
if (autoDecrypt && value.startsWith(ENCRYPTED_WARPER_PREFIX + "(") && value.endsWith(")")) {
try {
value = SecurityUtil.decrypt(value, true);