Skip to content

Commit b922b87

Browse files
committed
Add the constructors of DirectByteBuffer for old Android
1 parent a412f09 commit b922b87

File tree

2 files changed

+64
-12
lines changed

2 files changed

+64
-12
lines changed

msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBuffer.java

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,18 @@ public class MessageBuffer {
2727
static final Constructor byteBufferConstructor;
2828

2929
static final Class<?> directByteBufferClass;
30-
static final boolean isByteBufferConstructorTakesBufferReference;
30+
static final DirectBufferConstructorType directBufferConstructorType;
31+
static final Method memoryBlockWrapFromJni;
3132
static final int ARRAY_BYTE_BASE_OFFSET;
3233
static final int ARRAY_BYTE_INDEX_SCALE;
3334

35+
enum DirectBufferConstructorType {
36+
ARGS_LONG_INT_REF,
37+
ARGS_LONG_INT,
38+
ARGS_INT_INT,
39+
ARGS_MB_INT_INT
40+
}
41+
3442
static {
3543
try {
3644
// Check java version
@@ -82,19 +90,35 @@ public class MessageBuffer {
8290
// Find the hidden constructor for DirectByteBuffer
8391
directByteBufferClass = ClassLoader.getSystemClassLoader().loadClass("java.nio.DirectByteBuffer");
8492
Constructor directByteBufferConstructor = null;
85-
boolean isAcceptReference = true;
93+
DirectBufferConstructorType constructorType = null;
94+
Method mbWrap = null;
8695
try {
8796
// TODO We should use MethodHandle for Java7, which can avoid the cost of boxing with JIT optimization
8897
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(long.class, int.class, Object.class);
98+
constructorType = DirectBufferConstructorType.ARGS_LONG_INT_REF;
8999
}
90-
catch(NoSuchMethodException e) {
91-
// https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/java/nio/DirectByteBuffer.java
92-
// DirectByteBuffer(long address, int capacity)
93-
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(long.class, int.class);
94-
isAcceptReference = false;
100+
catch(NoSuchMethodException e0) {
101+
try {
102+
// https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/java/nio/DirectByteBuffer.java
103+
// DirectByteBuffer(long address, int capacity)
104+
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(long.class, int.class);
105+
constructorType = DirectBufferConstructorType.ARGS_LONG_INT;
106+
} catch (NoSuchMethodException e1) {
107+
try {
108+
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(int.class, int.class);
109+
constructorType = DirectBufferConstructorType.ARGS_INT_INT;
110+
} catch (NoSuchMethodException e2) {
111+
Class<?> aClass = Class.forName("java.nio.MemoryBlock");
112+
mbWrap = aClass.getDeclaredMethod("wrapFromJni", int.class, long.class);
113+
mbWrap.setAccessible(true);
114+
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(aClass, int.class, int.class);
115+
constructorType = DirectBufferConstructorType.ARGS_MB_INT_INT;
116+
}
117+
}
95118
}
96119
byteBufferConstructor = directByteBufferConstructor;
97-
isByteBufferConstructorTakesBufferReference = isAcceptReference;
120+
directBufferConstructorType = constructorType;
121+
memoryBlockWrapFromJni = mbWrap;
98122
if(byteBufferConstructor == null)
99123
throw new RuntimeException("Constructor of DirectByteBuffer is not found");
100124

@@ -510,10 +534,26 @@ public ByteBuffer toByteBuffer(int index, int length) {
510534
return ByteBuffer.wrap((byte[]) base, (int) ((address - ARRAY_BYTE_BASE_OFFSET) + index), length);
511535
}
512536
try {
513-
if(isByteBufferConstructorTakesBufferReference)
514-
return (ByteBuffer) byteBufferConstructor.newInstance(address + index, length, reference);
515-
else
516-
return (ByteBuffer) byteBufferConstructor.newInstance(address + index, length);
537+
ByteBuffer bb = null;
538+
switch (directBufferConstructorType) {
539+
case ARGS_LONG_INT_REF:
540+
bb = (ByteBuffer) byteBufferConstructor.newInstance(address + index, length, reference);
541+
break;
542+
case ARGS_LONG_INT:
543+
bb = (ByteBuffer) byteBufferConstructor.newInstance(address + index, length);
544+
break;
545+
case ARGS_INT_INT:
546+
bb = (ByteBuffer) byteBufferConstructor.newInstance((int)address + index, length);
547+
break;
548+
case ARGS_MB_INT_INT:
549+
bb = (ByteBuffer) byteBufferConstructor.newInstance(
550+
memoryBlockWrapFromJni.invoke(null, address + index, length),
551+
length, 0);
552+
break;
553+
default:
554+
throw new IllegalStateException("Unexpected value");
555+
}
556+
return bb;
517557
}
518558
catch(Throwable e) {
519559
// Convert checked exception to unchecked exception

msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferTest.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,18 @@ class MessageBufferTest extends MessagePackSpec {
112112

113113
}
114114

115+
"convert to ByteBuffer" in {
116+
for (t <- Seq(
117+
MessageBuffer.newBuffer(10),
118+
MessageBuffer.newDirectBuffer(10),
119+
MessageBuffer.newOffHeapBuffer(10))
120+
) {
121+
val bb = t.toByteBuffer
122+
bb.position shouldBe 0
123+
bb.limit shouldBe 10
124+
bb.capacity shouldBe 10
125+
}
126+
}
115127
}
116128

117129
}

0 commit comments

Comments
 (0)