[ROCKETMQ-259]Fix too many reflection calls when decode remoting command header
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/f613c3b7 Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/f613c3b7 Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/f613c3b7 Branch: refs/heads/master Commit: f613c3b7dfefc1cea15d8aa22fec763995a624e7 Parents: f091203 Author: yukon <yu...@apache.org> Authored: Fri Aug 11 19:15:38 2017 +0800 Committer: yukon <yu...@apache.org> Committed: Fri Aug 11 22:14:56 2017 +0800 ---------------------------------------------------------------------- .../remoting/protocol/RemotingCommand.java | 20 ++++++-------- .../remoting/protocol/RemotingCommandTest.java | 29 ++++++++++++++++++++ 2 files changed, 37 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/f613c3b7/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java ---------------------------------------------------------------------- diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java index bee9b12..2f8cb38 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java @@ -43,7 +43,7 @@ public class RemotingCommand { private static final Map<Class, String> CANONICAL_NAME_CACHE = new HashMap<Class, String>(); // 1, Oneway // 1, RESPONSE_COMMAND - private static final Map<Field, Annotation> NOT_NULL_ANNOTATION_CACHE = new HashMap<Field, Annotation>(); + private static final Map<Field, Boolean> NULLABLE_FIELD_CACHE = new HashMap<Field, Boolean>(); private static final String STRING_CANONICAL_NAME = String.class.getCanonicalName(); private static final String DOUBLE_CANONICAL_NAME_1 = Double.class.getCanonicalName(); private static final String DOUBLE_CANONICAL_NAME_2 = double.class.getCanonicalName(); @@ -252,11 +252,9 @@ public class RemotingCommand { try { String value = this.extFields.get(fieldName); if (null == value) { - Annotation annotation = getNotNullAnnotation(field); - if (annotation != null) { + if (!isFieldNullable(field)) { throw new RemotingCommandException("the custom field <" + fieldName + "> is null"); } - continue; } @@ -305,16 +303,14 @@ public class RemotingCommand { return field; } - private Annotation getNotNullAnnotation(Field field) { - Annotation annotation = NOT_NULL_ANNOTATION_CACHE.get(field); - - if (annotation == null) { - annotation = field.getAnnotation(CFNotNull.class); - synchronized (NOT_NULL_ANNOTATION_CACHE) { - NOT_NULL_ANNOTATION_CACHE.put(field, annotation); + private boolean isFieldNullable(Field field) { + if (!NULLABLE_FIELD_CACHE.containsKey(field)) { + Annotation annotation = field.getAnnotation(CFNotNull.class); + synchronized (NULLABLE_FIELD_CACHE) { + NULLABLE_FIELD_CACHE.put(field, annotation == null); } } - return annotation; + return NULLABLE_FIELD_CACHE.get(field); } private String getCanonicalName(Class clazz) { http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/f613c3b7/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingCommandTest.java ---------------------------------------------------------------------- diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingCommandTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingCommandTest.java index e11915b..2bd41ce 100644 --- a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingCommandTest.java +++ b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingCommandTest.java @@ -16,8 +16,11 @@ */ package org.apache.rocketmq.remoting.protocol; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.nio.ByteBuffer; import org.apache.rocketmq.remoting.CommandCustomHeader; +import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.junit.Test; @@ -179,6 +182,32 @@ public class RemotingCommandTest { assertThat(((ExtFieldsHeader) decodedHeader).isBooleanValue()).isEqualTo(true); assertThat(((ExtFieldsHeader) decodedHeader).getDoubleValue()).isBetween(0.617, 0.619); } + + @Test + public void testNotNullField() throws Exception { + RemotingCommand remotingCommand = new RemotingCommand(); + Method method = RemotingCommand.class.getDeclaredMethod("isFieldNullable", Field.class); + method.setAccessible(true); + + Field nullString = FieldTestClass.class.getDeclaredField("nullString"); + assertThat(method.invoke(remotingCommand, nullString)).isEqualTo(false); + + Field nullableString = FieldTestClass.class.getDeclaredField("nullable"); + assertThat(method.invoke(remotingCommand, nullableString)).isEqualTo(true); + + Field value = FieldTestClass.class.getDeclaredField("value"); + assertThat(method.invoke(remotingCommand, value)).isEqualTo(false); + } +} + +class FieldTestClass { + @CFNotNull + String nullString = null; + + String nullable = null; + + @CFNotNull + String value = "NotNull"; } class SampleCommandCustomHeader implements CommandCustomHeader {