Skip to content

Commit c361246

Browse files
Feature2.5.1 (#292)
* replaced String.format(0x%02X, i) with better performance api, 100 times faster via byte operations: 10k loads performace: 317ms vs 2ms * refactoring * refactoring * refactoring * @config added boolean trim (default=true) falag to allow configuration items to keep space when set trim=false * @config added boolean trim (default=true) falag to allow configuration items to keep space when set trim=false * update lib * security enhancement * release 2.5.1
1 parent c51286c commit c361246

File tree

8 files changed

+106
-41
lines changed

8 files changed

+106
-41
lines changed

pom.xml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
<modelVersion>4.0.0</modelVersion>
55
<groupId>org.summerboot</groupId>
66
<artifactId>jexpress</artifactId>
7-
<version>2.5.0</version>
7+
<version>2.5.1</version>
88
<packaging>jar</packaging>
9-
<name>Summer Boot jExpress</name>
9+
<name>Summer Boot jExpress ${version}</name>
1010
<description>Summer Boot jExpress focuses on solving non-functional and operational maintainability requirements,
1111
some of which Spring Boot has (may) not yet provided
1212
</description>
@@ -182,7 +182,7 @@
182182
<!-- <maven.compiler.source>21</maven.compiler.source>-->
183183
<!-- <maven.compiler.target>21</maven.compiler.target>-->
184184
<maven.compiler.release>21</maven.compiler.release>
185-
<maven-clean.version>3.4.0</maven-clean.version>
185+
<maven-clean.version>3.4.1</maven-clean.version>
186186
<maven-compiler.version>3.13.0</maven-compiler.version>
187187
<maven-dependency.version>3.8.1</maven-dependency.version>
188188
<maven-jar.version>3.4.2</maven-jar.version>
@@ -206,8 +206,8 @@
206206
<jwt.version>0.12.6</jwt.version>
207207

208208
<!-- NIO Netty -->
209-
<netty.version>4.1.117.Final</netty.version>
210-
<netty-tcnative.version>2.0.69.Final</netty-tcnative.version>
209+
<netty.version>4.1.119.Final</netty.version>
210+
<netty-tcnative.version>2.0.70.Final</netty-tcnative.version>
211211
<!-- gRPC and protobuf -->
212212
<grpc.version>1.70.0</grpc.version>
213213
<guava.version>33.4.0-jre</guava.version>
@@ -218,7 +218,7 @@
218218

219219

220220
<!-- MIME-Type -->
221-
<tika.version>3.0.0</tika.version>
221+
<tika.version>3.1.0</tika.version>
222222
<!-- JAX-RS -->
223223
<rs-api.version>4.0.0</rs-api.version>
224224
<jakarta.annotation.version>3.0.0</jakarta.annotation.version>
@@ -228,14 +228,14 @@
228228
<jackson.version>2.18.2</jackson.version>
229229
<!-- Bean Validation -->
230230
<jakarta.el.version>6.0.1</jakarta.el.version>
231-
<tomcat-embed-el.version>11.0.2</tomcat-embed-el.version>
231+
<tomcat-embed-el.version>11.0.4</tomcat-embed-el.version>
232232
<hibernate-validator.version>8.0.2.Final</hibernate-validator.version>
233233

234234
<!-- IOC Injection -->
235235
<guice.version>7.0.0</guice.version>
236236

237237
<!-- JPA -->
238-
<hibernate.version>6.6.5.Final</hibernate.version>
238+
<hibernate.version>6.6.9.Final</hibernate.version>
239239
<hikari-cp.version>6.2.1</hikari-cp.version>
240240

241241
<!-- Cache -->
@@ -254,11 +254,11 @@
254254
<openhtml.version>1.0.10</openhtml.version>
255255
<batik-transcoder.version>1.18</batik-transcoder.version>
256256
<!-- PDF - iText -->
257-
<itext7-core.version>9.0.0</itext7-core.version>
258-
<itext7-html2pdf.version>6.0.0</itext7-html2pdf.version>
257+
<itext7-core.version>9.1.0</itext7-core.version>
258+
<itext7-html2pdf.version>6.1.0</itext7-html2pdf.version>
259259

260260
<!-- Testing -->
261-
<testng.version>7.10.2</testng.version>
261+
<testng.version>7.11.0</testng.version>
262262
<jdbc.version>9.2.0</jdbc.version>
263263
</properties>
264264

src/main/java/org/summerboot/jexpress/boot/BackOffice.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ public Map<Integer, Integer> getBootErrorCodeMapping() {
314314
@Config(key = "naming.cli.psv", defaultValue = "psv")
315315
private String cliName_psv = "psv";
316316

317-
@Config(key = "naming.memo.delimiter", defaultValue = ": ")
317+
@Config(key = "naming.memo.delimiter", defaultValue = ": ", trim = false)
318318
private String memoDelimiter = ": ";
319319

320320
public Set<String> getRootPackageNames() {

src/main/java/org/summerboot/jexpress/boot/BootConstant.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,18 @@
1717

1818
import org.apache.logging.log4j.Level;
1919

20-
import java.util.Random;
20+
import java.security.SecureRandom;
2121

2222
/**
2323
* @author Changski Tie Zheng Zhang 张铁铮, 魏泽北, 杜旺财, 杜富贵
2424
*/
2525
public interface BootConstant {
2626

27-
String APP_ID = String.format("%06d", new Random().nextInt(999999));
27+
int APP_ID_VALUE = new SecureRandom().nextInt(999999);
28+
String APP_ID = String.format("%06d", APP_ID_VALUE);
2829

2930
//version
30-
String VERSION = "jExpress 2.5.0";
31+
String VERSION = "jExpress 2.5.1";
3132
String JEXPRESS_PACKAGE_NAME = "org.summerboot.jexpress";
3233

3334
String DEFAULT_ADMIN_MM = "changeit";

src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ protected void loadField(Field field, String configFolder, ConfigUtil helper, Pr
274274
}
275275
boolean isSpecifiedInCfgFile = props.containsKey(annotationKey);
276276
if (isSpecifiedInCfgFile) {// 2. empty cfg value as null
277-
Object nullValue = ReflectionUtil.toStandardJavaType(null, field.getType(), false, false, null);
277+
Object nullValue = ReflectionUtil.toStandardJavaType(null, false, field.getType(), false, false, null);
278278
field.set(this, nullValue);
279279
return;
280280
} else {

src/main/java/org/summerboot/jexpress/boot/config/annotation/Config.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,6 @@ public enum Validate {
6262

6363
String collectionDelimiter() default ",";
6464

65+
boolean trim() default true;
66+
6567
}

src/main/java/org/summerboot/jexpress/nio/server/ws/rs/JaxRsRequestParameter.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -370,21 +370,21 @@ protected Object parse(String value, String defaultValue, ServiceContext context
370370
Err e = new Err(BootErrorCode.BAD_REQUEST_MISSING_REQUIRED_FILED, null, null, null, "Missing Required Filed: " + type + "{" + key + "}=" + value);
371371
context.status(HttpResponseStatus.BAD_REQUEST).error(e);
372372
}
373-
return ReflectionUtil.toStandardJavaType(null, targetClass, false, false, null);//primitive types devault value or null
373+
return ReflectionUtil.toStandardJavaType(null, false, targetClass, false, false, null);//primitive types devault value or null
374374
}
375375
}
376376
String regex = pattern == null ? null : pattern.regexp();
377377
if (regex != null && !value.matches(regex)) {
378378
Err e = new Err(BootErrorCode.BAD_REQUEST_DATA, null, null, null, "Failed to parse data type: invalid " + type + "{" + key + "}=" + value + " by regex=" + regex);
379379
context.status(HttpResponseStatus.BAD_REQUEST).error(e);
380-
return ReflectionUtil.toStandardJavaType(null, targetClass, false, false, null);//primitive types devault value or null
380+
return ReflectionUtil.toStandardJavaType(null, false, targetClass, false, false, null);//primitive types devault value or null
381381
}
382382
try {
383-
return ReflectionUtil.toJavaType(targetClass, parameterizedType, value, false, false, enumConvert, collectionDelimiter);
383+
return ReflectionUtil.toJavaType(targetClass, parameterizedType, value, true, false, false, enumConvert, collectionDelimiter);
384384
} catch (Throwable ex) {
385385
Err e = new Err(BootErrorCode.BAD_REQUEST_DATA, null, null, ex, "Failed to parse data type: invalid " + type + "{" + key + "}=" + value);
386386
context.status(HttpResponseStatus.BAD_REQUEST).error(e);
387-
return ReflectionUtil.toStandardJavaType(null, targetClass, false, false, null);//primitive types devault value or null
387+
return ReflectionUtil.toStandardJavaType(null, false, targetClass, false, false, null);//primitive types devault value or null
388388
}
389389
}
390390
}

src/main/java/org/summerboot/jexpress/util/FormatterUtil.java

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.apache.commons.lang3.StringUtils;
2020
import org.apache.logging.log4j.LogManager;
2121
import org.apache.logging.log4j.Logger;
22+
import org.summerboot.jexpress.boot.BootConstant;
2223
import org.summerboot.jexpress.security.SecurityUtil;
2324

2425
import javax.imageio.ImageIO;
@@ -288,39 +289,93 @@ public static byte[] toByteArray(BufferedImage bi, String format) throws IOExcep
288289
}
289290

290291
public static String toString(ByteBuffer buffer) {
291-
return toString(buffer, true, true, 8, " ");
292+
return toString(buffer, true, true, 10, "\t");
292293
}
293294

294-
public static String toString(ByteBuffer buffer, boolean showStatus, boolean showHeaderfooter, int showNumberOfBytesPerLine, String delimiter) {
295+
public static String toString(ByteBuffer buffer, boolean showStatus, boolean showHeaderfooter, int numberOfBytesPerLine) {
296+
return toString(buffer, showStatus, showHeaderfooter, numberOfBytesPerLine, "\t");
297+
}
298+
299+
public static String toString(ByteBuffer buffer, boolean showStatus, boolean showHeaderfooter, int numberOfBytesPerLine, String delimiter) {
300+
return toString(buffer, showStatus, showHeaderfooter, numberOfBytesPerLine, delimiter, BootConstant.BR, "ByteBuffer Contents starts", "ByteBuffer Contents ends");
301+
}
302+
303+
public static String toString(ByteBuffer buffer, boolean showStatus, boolean showHeaderfooter, int numberOfBytesPerLine, String delimiter, String br, String header, String footer) {
304+
if (buffer == null) {
305+
return "";
306+
}
307+
if (br == null) {
308+
br = BootConstant.BR;
309+
}
295310
StringBuilder sb = new StringBuilder();
296311
if (showStatus) {
297312
sb.append("ByteBuffer status:")
298313
.append(" Order=").append(buffer.order())
299314
.append(" Position=").append(buffer.position())
300315
.append(" Limit=").append(buffer.limit())
301316
.append(" Capacity=").append(buffer.capacity())
302-
.append(" Remaining=").append(buffer.remaining());
317+
.append(" Remaining=").append(buffer.remaining())
318+
.append(br);
303319
}
304320
if (showHeaderfooter) {
305-
sb.append("\n************** ByteBuffer Contents starts **************\n");
321+
buuldHeaderfooter(header, numberOfBytesPerLine, delimiter, sb, br);
306322
}
307323
boolean eol = false;
308-
if (showNumberOfBytesPerLine > 0) {
324+
if (numberOfBytesPerLine > 0) {
309325
byte[] array = buffer.array();
310326
for (int i = 0; i < buffer.limit(); i++) {
311-
eol = (i + 1) % showNumberOfBytesPerLine == 0;
312-
sb.append(String.format("0x%02X", array[i])).append(eol ? "\n" : delimiter);
327+
eol = (i + 1) % numberOfBytesPerLine == 0;
328+
//String hexChars = String.format("0x%02X", array[i]);
329+
// replaced String.format("0x%02X", i) with better performance api, 100 times faster via byte operations: 10k loads performace: 317ms vs 2ms
330+
char[] hexChars = toString(array[i], true);
331+
sb.append(hexChars).append(eol ? br : delimiter);
313332
}
314333
}
315334
if (showHeaderfooter) {
316335
if (!eol) {
317336
sb.append("\n");
318337
}
319-
sb.append("************** ByteBuffer Contents ends **************\n");
338+
buuldHeaderfooter(footer, numberOfBytesPerLine, delimiter, sb, br);
320339
}
321340
return sb.toString();
322341
}
323342

343+
public static final short HEX_STRING_SIZE = 4;
344+
public static final char[] HexArrayIndexTable = "0123456789ABCDEF".toCharArray();
345+
346+
private static void buuldHeaderfooter(String title, int numberOfBytesPerLine, String delimiter, StringBuilder sb, String br) {
347+
int delimiterSize = delimiter.equals("\t") ? 4 : delimiter.length();
348+
int lineSize = HEX_STRING_SIZE * numberOfBytesPerLine + delimiterSize * (numberOfBytesPerLine - 1);
349+
int titleSize = title.length() + 2;
350+
int totalAsteriskSize = lineSize - titleSize;
351+
int asteriskSize = Math.max(2, totalAsteriskSize / 2 + totalAsteriskSize % 2);
352+
String asteriskLine = StringUtils.repeat("*", asteriskSize);
353+
sb.append(asteriskLine).append(" ").append(title).append(" ").append(asteriskLine).append(br);
354+
}
355+
356+
/**
357+
* replaced String.format("0x%02X", i) with better performance api, 100 times faster via byte operations: 10k loads performace: 317ms vs 2ms
358+
*
359+
* @param v
360+
* @return
361+
*/
362+
public static char[] toString(byte v, boolean append0x) {
363+
int b = v & 0xFF;
364+
char[] hexChars;
365+
if (append0x) {
366+
hexChars = new char[4];
367+
hexChars[0] = '0';
368+
hexChars[1] = 'x';
369+
hexChars[2] = HexArrayIndexTable[b >>> 4];
370+
hexChars[3] = HexArrayIndexTable[b & 0x0F];
371+
} else {
372+
hexChars = new char[2];
373+
hexChars[0] = HexArrayIndexTable[b >>> 4];
374+
hexChars[1] = HexArrayIndexTable[b & 0x0F];
375+
}
376+
return hexChars;
377+
}
378+
324379
/**
325380
* For old Java before Java 17 HexFormat.of().parseHex(s)
326381
*

src/main/java/org/summerboot/jexpress/util/ReflectionUtil.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.common.collect.ImmutableSortedSet;
2121
import org.apache.commons.lang3.StringUtils;
2222
import org.reflections.Reflections;
23+
import org.summerboot.jexpress.boot.config.annotation.Config;
2324
import org.summerboot.jexpress.nio.server.ws.rs.EnumConvert;
2425
import org.summerboot.jexpress.security.SecurityUtil;
2526

@@ -209,19 +210,23 @@ public static void loadField(Object instance, Field field, String value, final b
209210
Class targetClass = field.getType();
210211
Type genericType = field.getGenericType();
211212
field.setAccessible(true);
212-
field.set(instance, toJavaType(targetClass, genericType, value, autoDecrypt, isEmailRecipients, null, collectionDelimiter));
213+
Config cfgSettings = field.getAnnotation(Config.class);
214+
boolean trim = cfgSettings == null ? false : cfgSettings.trim();
215+
field.set(instance, toJavaType(targetClass, genericType, value, trim, autoDecrypt, isEmailRecipients, null, collectionDelimiter));
213216
}
214217

215218
protected static final Type[] DEFAULT_ARG_TYPES = {String.class, String.class};
216219

217-
public static Object toJavaType(Class targetClass, Type genericType, String value, final boolean autoDecrypt,
220+
public static Object toJavaType(Class targetClass, Type genericType, String value, final boolean trim, final boolean autoDecrypt,
218221
final boolean isEmailRecipients, EnumConvert.To enumConvert, String collectionDelimiter) throws IllegalAccessException {
219222
if (StringUtils.isBlank(value)) {
220-
Object nullValue = ReflectionUtil.toStandardJavaType(null, targetClass, autoDecrypt, false, enumConvert);
223+
Object nullValue = ReflectionUtil.toStandardJavaType(null, trim, targetClass, autoDecrypt, false, enumConvert);
221224
return nullValue;
222225
}
223226

224-
value = value.trim();
227+
if (trim) {
228+
value = value.trim();
229+
}
225230
// Class targetClass = field.getType();
226231
// Type genericType = field.getGenericType();
227232
Type[] argTypes = DEFAULT_ARG_TYPES;
@@ -253,7 +258,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
253258
Class classT = targetClass.getComponentType();
254259
Object array = Array.newInstance(classT, valuesStr.length);
255260
for (int i = 0; i < valuesStr.length; i++) {
256-
Array.set(array, i, toStandardJavaType(valuesStr[i], classT, autoDecrypt, isEmailRecipients, enumConvert));
261+
Array.set(array, i, toStandardJavaType(valuesStr[i], trim, classT, autoDecrypt, isEmailRecipients, enumConvert));
257262
}
258263
return array;
259264
} else if (targetClass.equals(Set.class)) {
@@ -264,7 +269,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
264269
Class classT = upperBoundClasses[0];//(Class) argTypes[0];
265270
Object array = Array.newInstance(classT, valuesStr.length);
266271
for (int i = 0; i < valuesStr.length; i++) {
267-
Array.set(array, i, toStandardJavaType(valuesStr[i], classT, autoDecrypt, isEmailRecipients, enumConvert));
272+
Array.set(array, i, toStandardJavaType(valuesStr[i], trim, classT, autoDecrypt, isEmailRecipients, enumConvert));
268273
}
269274
return Set.of((Object[]) array);
270275
} else if (targetClass.equals(SortedSet.class)) {
@@ -275,7 +280,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
275280
Class classT = upperBoundClasses[0];//(Class) argTypes[0];
276281
Object array = Array.newInstance(classT, valuesStr.length);
277282
for (int i = 0; i < valuesStr.length; i++) {
278-
Array.set(array, i, toStandardJavaType(valuesStr[i], classT, autoDecrypt, isEmailRecipients, enumConvert));
283+
Array.set(array, i, toStandardJavaType(valuesStr[i], trim, classT, autoDecrypt, isEmailRecipients, enumConvert));
279284
}
280285
return ImmutableSortedSet.copyOf(List.of((Object[]) array));
281286
} else if (targetClass.equals(List.class)) {
@@ -286,7 +291,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
286291
Class classT = upperBoundClasses[0];//(Class) argTypes[0];
287292
Object array = Array.newInstance(classT, valuesStr.length);
288293
for (int i = 0; i < valuesStr.length; i++) {
289-
Array.set(array, i, toStandardJavaType(valuesStr[i], classT, autoDecrypt, isEmailRecipients, enumConvert));
294+
Array.set(array, i, toStandardJavaType(valuesStr[i], trim, classT, autoDecrypt, isEmailRecipients, enumConvert));
290295
}
291296
return List.of((Object[]) array);
292297
} else if (targetClass.equals(Map.class)) {
@@ -299,8 +304,8 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
299304
Map ret = new HashMap();
300305
for (var k : stringMap.keySet()) {
301306
String v = stringMap.get(k);
302-
Object keyT = toStandardJavaType(k, classT1, autoDecrypt, isEmailRecipients, enumConvert);
303-
Object valueT = toStandardJavaType(v, classT2, autoDecrypt, isEmailRecipients, enumConvert);
307+
Object keyT = toStandardJavaType(k, trim, classT1, autoDecrypt, isEmailRecipients, enumConvert);
308+
Object valueT = toStandardJavaType(v, trim, classT2, autoDecrypt, isEmailRecipients, enumConvert);
304309
ret.put(keyT, valueT);
305310
}
306311
return Map.copyOf(ret);
@@ -321,7 +326,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
321326
throw new IllegalArgumentException("invalid json data: " + value, ex);
322327
}
323328
} else {
324-
Object v = toStandardJavaType(value, targetClass, autoDecrypt, isEmailRecipients, enumConvert);
329+
Object v = toStandardJavaType(value, trim, targetClass, autoDecrypt, isEmailRecipients, enumConvert);
325330
return v;
326331
}
327332
}
@@ -337,7 +342,7 @@ public static Object toJavaType(Class targetClass, Type genericType, String valu
337342
* @param isEmailRecipients
338343
* @return
339344
*/
340-
public static Object toStandardJavaType(String value, final Class targetClass, final boolean autoDecrypt,
345+
public static Object toStandardJavaType(String value, final boolean trim, final Class targetClass, final boolean autoDecrypt,
341346
final boolean isEmailRecipients, EnumConvert.To enumConvert) {
342347
if (StringUtils.isBlank(value)) {
343348
if (targetClass.equals(boolean.class)) {
@@ -357,7 +362,9 @@ public static Object toStandardJavaType(String value, final Class targetClass, f
357362
return null;
358363
}
359364
}
360-
value = value.trim();
365+
if (trim) {
366+
value = value.trim();
367+
}
361368
if (autoDecrypt && value.startsWith(ENCRYPTED_WARPER_PREFIX + "(") && value.endsWith(")")) {
362369
try {
363370
value = SecurityUtil.decrypt(value, true);

0 commit comments

Comments
 (0)