BufferRecyclersDatabindTest.java
package com.fasterxml.jackson.databind.util;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.nio.charset.StandardCharsets;
import java.util.function.Predicate;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.util.BufferRecycler;
import com.fasterxml.jackson.core.util.JsonRecyclerPools;
import com.fasterxml.jackson.core.util.RecyclerPool;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.assertEquals;
// For [databind#4321]: basic test
public class BufferRecyclersDatabindTest extends DatabindTestUtil
{
@JsonPropertyOrder({ "a", "b" })
static class Pojo4321 {
public int a;
public String b;
public Pojo4321(int a, String b) {
this.a = a;
this.b = b;
}
protected Pojo4321() { }
}
// // Parsers with RecyclerPools:
@Test
public void testParserWithThreadLocalPool() throws Exception {
_testParser(JsonRecyclerPools.threadLocalPool());
}
@Test
public void testParserWithNopLocalPool() throws Exception {
_testParser(JsonRecyclerPools.nonRecyclingPool());
}
@Test
public void testParserWithDequeuPool() throws Exception {
_testParser(JsonRecyclerPools.newConcurrentDequePool());
_testParser(JsonRecyclerPools.sharedConcurrentDequePool());
}
@Test
@Deprecated // tests deprecated impl
public void testParserWithLockFreePool() throws Exception {
_testParser(JsonRecyclerPools.newLockFreePool());
_testParser(JsonRecyclerPools.sharedLockFreePool());
}
@Test
public void testParserWithBoundedPool() throws Exception {
_testParser(JsonRecyclerPools.newBoundedPool(5));
_testParser(JsonRecyclerPools.sharedBoundedPool());
}
@Test
public void testParserWithHybridPool() throws Exception {
_testParser(new HybridTestPool());
}
private void _testParser(RecyclerPool<BufferRecycler> pool) throws Exception
{
ObjectMapper mapper = JsonMapper.builder(
JsonFactory.builder()
.recyclerPool(pool)
.build()).build();
final String DOC = "{\"a\":123,\"b\":\"foobar\"}";
// Let's first test using char-backed parser
Pojo4321 value = mapper.readerFor(Pojo4321.class)
.readValue(DOC);
assertEquals(123, value.a);
assertEquals("foobar", value.b);
// and then byte-backed parser
value = mapper.readerFor(Pojo4321.class)
.readValue(utf8Bytes(DOC));
assertEquals(123, value.a);
assertEquals("foobar", value.b);
}
// // Generators with RecyclerPools:
@Test
public void testGeneratorWithThreadLocalPool() throws Exception {
_testGenerator(JsonRecyclerPools.threadLocalPool());
}
@Test
public void testGeneratorWithNopLocalPool() throws Exception {
_testGenerator(JsonRecyclerPools.nonRecyclingPool());
}
@Test
public void testGeneratorWithDequeuPool() throws Exception {
_testGenerator(JsonRecyclerPools.newConcurrentDequePool());
_testGenerator(JsonRecyclerPools.sharedConcurrentDequePool());
}
@Test
@Deprecated // tests deprecated impl
public void testGeneratorWithLockFreePool() throws Exception {
_testGenerator(JsonRecyclerPools.newLockFreePool());
_testGenerator(JsonRecyclerPools.sharedLockFreePool());
}
@Test
public void testGeneratorWithBoundedPool() throws Exception {
_testGenerator(JsonRecyclerPools.newBoundedPool(5));
_testGenerator(JsonRecyclerPools.sharedBoundedPool());
}
@Test
public void testGeneratorWithHybridPool() throws Exception {
_testGenerator(new HybridTestPool());
}
private void _testGenerator(RecyclerPool<BufferRecycler> pool) throws Exception
{
ObjectMapper mapper = JsonMapper.builder(
JsonFactory.builder()
.recyclerPool(pool)
.build()).build();
final String EXP = "{\"a\":-42,\"b\":\"bogus\"}";
// First write as String
assertEquals(EXP, mapper.writeValueAsString(new Pojo4321(-42, "bogus")));
// and then as bytes
assertEquals(EXP, new String(mapper.writeValueAsBytes(new Pojo4321(-42, "bogus")),
StandardCharsets.UTF_8));
}
static class HybridTestPool implements RecyclerPool<BufferRecycler>
{
private static final long serialVersionUID = 1L;
private static final Predicate<Thread> isVirtual = VirtualPredicate.findIsVirtualPredicate();
private final RecyclerPool<BufferRecycler> nativePool = JsonRecyclerPools.threadLocalPool();
private final RecyclerPool<BufferRecycler> virtualPool = JsonRecyclerPools.newConcurrentDequePool();
@Override
public BufferRecycler acquirePooled() {
return isVirtual.test(Thread.currentThread()) ?
virtualPool.acquirePooled() :
nativePool.acquirePooled();
}
@Override
public void releasePooled(BufferRecycler pooled) {
if (isVirtual.test(Thread.currentThread())) {
virtualPool.releasePooled(pooled);
} else {
nativePool.releasePooled(pooled);
}
}
static class VirtualPredicate {
static final MethodHandle virtualMh = findVirtualMH();
static MethodHandle findVirtualMH() {
try {
return MethodHandles.publicLookup().findVirtual(Thread.class, "isVirtual",
MethodType.methodType(boolean.class));
} catch (Exception e) {
return null;
}
}
static Predicate<Thread> findIsVirtualPredicate() {
if (virtualMh != null) {
return new Predicate<Thread>() {
@Override
public boolean test(Thread thread) {
try {
return (boolean) virtualMh.invokeExact(thread);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
};
}
return new Predicate<Thread>() {
@Override
public boolean test(Thread thread) {
return false;
}
};
}
}
}
}