diff --git a/json-core/pom.xml b/json-core/pom.xml
index cb5709e1..03b843e4 100644
--- a/json-core/pom.xml
+++ b/json-core/pom.xml
@@ -36,6 +36,42 @@
1.7
test
-
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ compile-java-21
+ compile
+
+ compile
+
+
+ 21
+
+
+ ${project.basedir}/src/main/java21
+
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ true
+
+
+
+
+
+
diff --git a/json-core/src/main/java/io/avaje/json/stream/core/HybridBufferRecycler.java b/json-core/src/main/java/io/avaje/json/stream/core/HybridBufferRecycler.java
index 394b060b..f0bf46b6 100644
--- a/json-core/src/main/java/io/avaje/json/stream/core/HybridBufferRecycler.java
+++ b/json-core/src/main/java/io/avaje/json/stream/core/HybridBufferRecycler.java
@@ -5,10 +5,7 @@
import java.io.InputStream;
import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
import java.util.concurrent.atomic.AtomicReferenceArray;
-import java.util.function.Predicate;
/**
* This is a custom implementation of the Jackson's RecyclerPool intended to work equally well with
@@ -37,10 +34,9 @@ final class HybridBufferRecycler implements BufferRecycler {
private static final HybridBufferRecycler INSTANCE = new HybridBufferRecycler();
- private static final Predicate isVirtual = VirtualPredicate.findIsVirtualPredicate();
-
private static final BufferRecycler NATIVE_RECYCLER = ThreadLocalPool.shared();
private static final BufferRecycler VIRTUAL_RECYCLER = StripedLockFreePool.shared();
+ private static final boolean VT_ENABLED = Runtime.version().feature() >= 21;
private HybridBufferRecycler() {
}
@@ -51,21 +47,21 @@ static HybridBufferRecycler shared() {
@Override
public JsonGenerator generator(JsonOutput target) {
- return isVirtual.test(Thread.currentThread())
+ return VT_ENABLED && ThreadFunctions.isVirtual()
? VIRTUAL_RECYCLER.generator(target)
: NATIVE_RECYCLER.generator(target);
}
@Override
public JsonParser parser(byte[] bytes) {
- return isVirtual.test(Thread.currentThread())
+ return VT_ENABLED && ThreadFunctions.isVirtual()
? VIRTUAL_RECYCLER.parser(bytes)
: NATIVE_RECYCLER.parser(bytes);
}
@Override
public JsonParser parser(InputStream in) {
- return isVirtual.test(Thread.currentThread())
+ return VT_ENABLED && ThreadFunctions.isVirtual()
? VIRTUAL_RECYCLER.parser(in)
: NATIVE_RECYCLER.parser(in);
}
@@ -131,9 +127,8 @@ public JsonGenerator generator(JsonOutput target) {
if (generatorStacks.compareAndSet(index, currentHead, currentHead.next)) {
currentHead.next = null;
return currentHead.value.prepare(target);
- } else {
- currentHead = generatorStacks.get(index);
}
+ currentHead = generatorStacks.get(index);
}
}
@@ -149,9 +144,8 @@ private JsonParser parser() {
if (parserStacks.compareAndSet(index, currentHead, currentHead.next)) {
currentHead.next = null;
return currentHead.value;
- } else {
- currentHead = parserStacks.get(index);
}
+ currentHead = parserStacks.get(index);
}
}
@@ -166,9 +160,8 @@ public void recycle(JsonGenerator recycler) {
if (generatorStacks.compareAndSet(vThreadBufferRecycler.slot, next, newHead)) {
newHead.next = next;
return;
- } else {
- next = generatorStacks.get(vThreadBufferRecycler.slot);
}
+ next = generatorStacks.get(vThreadBufferRecycler.slot);
}
}
@@ -183,9 +176,8 @@ public void recycle(JsonParser recycler) {
if (parserStacks.compareAndSet(vThreadBufferRecycler.slot, next, newHead)) {
newHead.next = next;
return;
- } else {
- next = parserStacks.get(vThreadBufferRecycler.slot);
}
+ next = parserStacks.get(vThreadBufferRecycler.slot);
}
}
@@ -236,35 +228,6 @@ private VThreadJParser(int slot) {
}
}
- private static final class VirtualPredicate {
- private static final MethodHandle virtualMh = findVirtualMH();
-
- private static MethodHandle findVirtualMH() {
- try {
- return MethodHandles.publicLookup()
- .findVirtual(Thread.class, "isVirtual", MethodType.methodType(boolean.class));
- } catch (Exception e) {
- return null;
- }
- }
-
- private static Predicate findIsVirtualPredicate() {
- return virtualMh == null ? VirtualPredicate::notVirtual : VirtualPredicate::isVirtual;
- }
-
- private static boolean isVirtual(Thread thread) {
- try {
- return (boolean) virtualMh.invokeExact(thread);
- } catch (Throwable e) {
- throw new RuntimeException(e);
- }
- }
-
- private static boolean notVirtual(Thread thread) {
- return false;
- }
- }
-
private static final class XorShiftThreadProbe {
private final int mask;
@@ -282,7 +245,7 @@ private int probe() {
// 0x9e3779b9 is the integral part of the Golden Ratio's fractional part 0.61803398875…
// (sqrt(5)-1)/2
// multiplied by 2^32, which has the best possible scattering properties.
- int probe = (int) ((Thread.currentThread().getId() * 0x9e3779b9) & Integer.MAX_VALUE);
+ int probe = (int) ((ThreadFunctions.getId() * 0x9e3779b9) & Integer.MAX_VALUE);
// xorshift
probe ^= probe << 13;
probe ^= probe >>> 17;
diff --git a/json-core/src/main/java/io/avaje/json/stream/core/ThreadFunctions.java b/json-core/src/main/java/io/avaje/json/stream/core/ThreadFunctions.java
new file mode 100644
index 00000000..71f82452
--- /dev/null
+++ b/json-core/src/main/java/io/avaje/json/stream/core/ThreadFunctions.java
@@ -0,0 +1,13 @@
+package io.avaje.json.stream.core;
+
+final class ThreadFunctions {
+ private ThreadFunctions() {}
+
+ static long getId() {
+ return Thread.currentThread().getId();
+ }
+
+ static boolean isVirtual() {
+ return false;
+ }
+}
diff --git a/json-core/src/main/java21/io/avaje/json/stream/core/ThreadFunctions.java b/json-core/src/main/java21/io/avaje/json/stream/core/ThreadFunctions.java
new file mode 100644
index 00000000..6048483c
--- /dev/null
+++ b/json-core/src/main/java21/io/avaje/json/stream/core/ThreadFunctions.java
@@ -0,0 +1,13 @@
+package io.avaje.json.stream.core;
+
+final class ThreadFunctions {
+ private ThreadFunctions() {}
+
+ static long getId() {
+ return Thread.currentThread().threadId();
+ }
+
+ static boolean isVirtual() {
+ return Thread.currentThread().isVirtual();
+ }
+}