Merge "Introduce cache schema for generic Struct class."
diff --git a/staticlibs/device/android/net/util/Struct.java b/staticlibs/device/android/net/util/Struct.java
index 92e05aa..03f5f22 100644
--- a/staticlibs/device/android/net/util/Struct.java
+++ b/staticlibs/device/android/net/util/Struct.java
@@ -29,6 +29,7 @@
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Define a generic class that helps to parse the structured message.
@@ -142,6 +143,7 @@
this.field = field;
}
}
+ private static ConcurrentHashMap<Class, FieldInfo[]> sFieldCache = new ConcurrentHashMap();
private static void checkAnnotationType(final Type type, final Class fieldType) {
switch (type) {
@@ -300,11 +302,15 @@
+ Struct.class.getName());
}
- final FieldInfo[] annotationFields = new FieldInfo[getAnnotationFieldCount(clazz)];
+ final FieldInfo[] cachedAnnotationFields = sFieldCache.get(clazz);
+ if (cachedAnnotationFields != null) {
+ return cachedAnnotationFields;
+ }
// Since array returned from Class#getDeclaredFields doesn't guarantee the actual order
// of field appeared in the class, that is a problem when parsing raw data read from
// ByteBuffer. Store the fields appeared by the order() defined in the Field annotation.
+ final FieldInfo[] annotationFields = new FieldInfo[getAnnotationFieldCount(clazz)];
for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers())) continue;
@@ -324,6 +330,7 @@
}
annotationFields[annotation.order()] = new FieldInfo(annotation, field);
}
+ sFieldCache.putIfAbsent(clazz, annotationFields);
return annotationFields;
}
diff --git a/staticlibs/tests/unit/src/android/net/util/StructTest.java b/staticlibs/tests/unit/src/android/net/util/StructTest.java
index 3451739..5ca278a 100644
--- a/staticlibs/tests/unit/src/android/net/util/StructTest.java
+++ b/staticlibs/tests/unit/src/android/net/util/StructTest.java
@@ -96,10 +96,7 @@
}
}
- @Test
- public void testClassWithExplicitConstructor() {
- final HeaderMsgWithConstructor msg = doParsingMessageTest(HDR_EMPTY,
- HeaderMsgWithConstructor.class);
+ private void verifyHeaderParsing(final HeaderMsgWithConstructor msg) {
assertEquals(10, msg.mFamily);
assertEquals(0, msg.mLen);
assertEquals(15715755, msg.mIfindex);
@@ -107,6 +104,13 @@
assertEquals(0, msg.mIcmpCode);
}
+ @Test
+ public void testClassWithExplicitConstructor() {
+ final HeaderMsgWithConstructor msg = doParsingMessageTest(HDR_EMPTY,
+ HeaderMsgWithConstructor.class);
+ verifyHeaderParsing(msg);
+ }
+
static class HeaderMsgWithoutConstructor extends Struct {
static int sType;
static int sLength;
@@ -367,21 +371,22 @@
}
}
- @Test
- public void testPrefixArrayField() throws Exception {
- final ByteBuffer buf = toByteBuffer(OPT_PREF64);
- buf.order(ByteOrder.LITTLE_ENDIAN);
-
+ private void verifyPrefixByteArrayParsing(final PrefixMessage msg) throws Exception {
// The original PREF64 option message has just 12 bytes for prefix byte array
// (Highest 96 bits of the Prefix), copyOf pads the 128-bits IPv6 address with
// prefix and 4-bytes zeros.
- final PrefixMessage msg = Struct.parse(PrefixMessage.class, buf);
final InetAddress addr = InetAddress.getByAddress(Arrays.copyOf(msg.mPrefix, 16));
final IpPrefix prefix = new IpPrefix(addr, 96);
assertEquals(10064, msg.mLifetime);
assertTrue(prefix.equals(new IpPrefix("2001:db8:3:4:5:6::/96")));
}
+ @Test
+ public void testPrefixArrayField() throws Exception {
+ final PrefixMessage msg = doParsingMessageTest(OPT_PREF64, PrefixMessage.class);
+ verifyPrefixByteArrayParsing(msg);
+ }
+
static class HeaderMessageWithMutableField extends Struct {
@Field(order = 0, type = Type.U8, padding = 1)
final short mFamily;
@@ -481,6 +486,18 @@
assertEquals(30806 /* 0x7856 */, msg.mInt2);
}
+ @Test
+ public void testClassesParsedFromCache() throws Exception {
+ for (int i = 0; i < 100; i++) {
+ final HeaderMsgWithConstructor msg1 =
+ doParsingMessageTest(HDR_EMPTY, HeaderMsgWithConstructor.class);
+ verifyHeaderParsing(msg1);
+
+ final PrefixMessage msg2 = doParsingMessageTest(OPT_PREF64, PrefixMessage.class);
+ verifyPrefixByteArrayParsing(msg2);
+ }
+ }
+
private ByteBuffer toByteBuffer(final String hexString) {
return ByteBuffer.wrap(HexDump.hexStringToByteArray(hexString));
}