Skip to content

Feature2.5.1 #292

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.summerboot</groupId>
<artifactId>jexpress</artifactId>
<version>2.5.0</version>
<version>2.5.1</version>
<packaging>jar</packaging>
<name>Summer Boot jExpress</name>
<name>Summer Boot jExpress ${version}</name>
<description>Summer Boot jExpress focuses on solving non-functional and operational maintainability requirements,
some of which Spring Boot has (may) not yet provided
</description>
Expand Down Expand Up @@ -182,7 +182,7 @@
<!-- <maven.compiler.source>21</maven.compiler.source>-->
<!-- <maven.compiler.target>21</maven.compiler.target>-->
<maven.compiler.release>21</maven.compiler.release>
<maven-clean.version>3.4.0</maven-clean.version>
<maven-clean.version>3.4.1</maven-clean.version>
<maven-compiler.version>3.13.0</maven-compiler.version>
<maven-dependency.version>3.8.1</maven-dependency.version>
<maven-jar.version>3.4.2</maven-jar.version>
Expand All @@ -206,8 +206,8 @@
<jwt.version>0.12.6</jwt.version>

<!-- NIO Netty -->
<netty.version>4.1.117.Final</netty.version>
<netty-tcnative.version>2.0.69.Final</netty-tcnative.version>
<netty.version>4.1.119.Final</netty.version>
<netty-tcnative.version>2.0.70.Final</netty-tcnative.version>
<!-- gRPC and protobuf -->
<grpc.version>1.70.0</grpc.version>
<guava.version>33.4.0-jre</guava.version>
Expand All @@ -218,7 +218,7 @@


<!-- MIME-Type -->
<tika.version>3.0.0</tika.version>
<tika.version>3.1.0</tika.version>
<!-- JAX-RS -->
<rs-api.version>4.0.0</rs-api.version>
<jakarta.annotation.version>3.0.0</jakarta.annotation.version>
Expand All @@ -228,14 +228,14 @@
<jackson.version>2.18.2</jackson.version>
<!-- Bean Validation -->
<jakarta.el.version>6.0.1</jakarta.el.version>
<tomcat-embed-el.version>11.0.2</tomcat-embed-el.version>
<tomcat-embed-el.version>11.0.4</tomcat-embed-el.version>
<hibernate-validator.version>8.0.2.Final</hibernate-validator.version>

<!-- IOC Injection -->
<guice.version>7.0.0</guice.version>

<!-- JPA -->
<hibernate.version>6.6.5.Final</hibernate.version>
<hibernate.version>6.6.9.Final</hibernate.version>
<hikari-cp.version>6.2.1</hikari-cp.version>

<!-- Cache -->
Expand All @@ -254,11 +254,11 @@
<openhtml.version>1.0.10</openhtml.version>
<batik-transcoder.version>1.18</batik-transcoder.version>
<!-- PDF - iText -->
<itext7-core.version>9.0.0</itext7-core.version>
<itext7-html2pdf.version>6.0.0</itext7-html2pdf.version>
<itext7-core.version>9.1.0</itext7-core.version>
<itext7-html2pdf.version>6.1.0</itext7-html2pdf.version>

<!-- Testing -->
<testng.version>7.10.2</testng.version>
<testng.version>7.11.0</testng.version>
<jdbc.version>9.2.0</jdbc.version>
</properties>

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/summerboot/jexpress/boot/BackOffice.java
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ public Map<Integer, Integer> 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<String> getRootPackageNames() {
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/org/summerboot/jexpress/boot/BootConstant.java
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,6 @@ public enum Validate {

String collectionDelimiter() default ",";

boolean trim() default true;

}
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
71 changes: 63 additions & 8 deletions src/main/java/org/summerboot/jexpress/util/FormatterUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -288,39 +289,93 @@ 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:")
.append(" Order=").append(buffer.order())
.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)
*
Expand Down
33 changes: 20 additions & 13 deletions src/main/java/org/summerboot/jexpress/util/ReflectionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)) {
Expand All @@ -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)) {
Expand All @@ -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)) {
Expand All @@ -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)) {
Expand All @@ -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);
Expand All @@ -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;
}
}
Expand All @@ -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)) {
Expand All @@ -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);
Expand Down
Loading