| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -41,7 +41,7 @@ class Codegen { | |||
| 41 | 41 | add(Vector.class); | |
| 42 | 42 | }}; | |
| 43 | 43 | static volatile Map<String, Decoder> cache = new HashMap<String, Decoder>(); | |
| 44 | - static List<Extension> fieldDecoderFactories = new ArrayList<Extension>(); | ||
| 44 | + static List<Extension> extensions = new ArrayList<Extension>(); | ||
| 45 | 45 | static ClassPool pool = ClassPool.getDefault(); | |
| 46 | 46 | ||
| 47 | 47 | static Decoder getDecoder(String cacheKey, Type type, Type... typeArgs) { | |
@@ -164,10 +164,51 @@ public static void addNewDecoder(String cacheKey, Decoder decoder) { | |||
| 164 | 164 | } | |
| 165 | 165 | ||
| 166 | 166 | private static String genObject(Class clazz, String cacheKey) { | |
| 167 | - Map<Integer, Object> map = new HashMap<Integer, Object>(); | ||
| 167 | + Map<Integer, Object> trieTree = buildTriTree(clazz); | ||
| 168 | + String newInstanceCode = null; | ||
| 169 | + for (Extension extension : extensions) { | ||
| 170 | + newInstanceCode = extension.codegenNewInstance(clazz); | ||
| 171 | + if (newInstanceCode != null) { | ||
| 172 | + break; | ||
| 173 | + } | ||
| 174 | + } | ||
| 175 | + if (newInstanceCode == null) { | ||
| 176 | + newInstanceCode = "new " + clazz.getCanonicalName() + "()"; | ||
| 177 | + } | ||
| 178 | + if (trieTree.isEmpty()) { | ||
| 179 | + StringBuilder lines = new StringBuilder(); | ||
| 180 | + append(lines, "public Object decode(com.jsoniter.Jsoniter iter) {"); | ||
| 181 | + append(lines, "{{clazz}} obj = {{newInst}};"); | ||
| 182 | + append(lines, "iter.skip();"); | ||
| 183 | + append(lines, "return obj;"); | ||
| 184 | + append(lines, "}"); | ||
| 185 | + return lines.toString().replace("{{clazz}}", clazz.getName()).replace("{{newInst}}", newInstanceCode); | ||
| 186 | + } | ||
| 187 | + StringBuilder lines = new StringBuilder(); | ||
| 188 | + append(lines, "public Object decode(com.jsoniter.Jsoniter iter) {"); | ||
| 189 | + append(lines, "{{clazz}} obj = {{newInst}};"); | ||
| 190 | + append(lines, "for (com.jsoniter.Slice field = iter.readObjectAsSlice(); field != null; field = iter.readObjectAsSlice()) {"); | ||
| 191 | + append(lines, "switch (field.len) {"); | ||
| 192 | + for (Map.Entry<Integer, Object> entry : trieTree.entrySet()) { | ||
| 193 | + Integer len = entry.getKey(); | ||
| 194 | + append(lines, "case " + len + ": "); | ||
| 195 | + Map<Byte, Object> current = (Map<Byte, Object>) entry.getValue(); | ||
| 196 | + addFieldDispatch(lines, len, 0, current, cacheKey); | ||
| 197 | + append(lines, "break;"); | ||
| 198 | + } | ||
| 199 | + append(lines, "}"); | ||
| 200 | + append(lines, "iter.skip();"); | ||
| 201 | + append(lines, "}"); | ||
| 202 | + append(lines, "return obj;"); | ||
| 203 | + append(lines, "}"); | ||
| 204 | + return lines.toString().replace("{{clazz}}", clazz.getName()).replace("{{newInst}}", newInstanceCode); | ||
| 205 | + } | ||
| 206 | + | ||
| 207 | + private static Map<Integer, Object> buildTriTree(Class clazz) { | ||
| 208 | + Map<Integer, Object> trieTree = new HashMap<Integer, Object>(); | ||
| 168 | 209 | for (Field field : clazz.getFields()) { | |
| 169 | 210 | String[] alternativeFieldNames = null; | |
| 170 | - for (Extension extension : fieldDecoderFactories) { | ||
| 211 | + for (Extension extension : extensions) { | ||
| 171 | 212 | alternativeFieldNames = extension.getAlternativeFieldNames(field); | |
| 172 | 213 | if (alternativeFieldNames != null) { | |
| 173 | 214 | break; | |
@@ -178,10 +219,10 @@ private static String genObject(Class clazz, String cacheKey) { | |||
| 178 | 219 | } | |
| 179 | 220 | for (String alternativeFieldName : alternativeFieldNames) { | |
| 180 | 221 | byte[] fieldName = alternativeFieldName.getBytes(); | |
| 181 | - Map<Byte, Object> current = (Map<Byte, Object>) map.get(fieldName.length); | ||
| 222 | + Map<Byte, Object> current = (Map<Byte, Object>) trieTree.get(fieldName.length); | ||
| 182 | 223 | if (current == null) { | |
| 183 | 224 | current = new HashMap<Byte, Object>(); | |
| 184 | - map.put(fieldName.length, current); | ||
| 225 | + trieTree.put(fieldName.length, current); | ||
| 185 | 226 | } | |
| 186 | 227 | for (int i = 0; i < fieldName.length - 1; i++) { | |
| 187 | 228 | byte b = fieldName[i]; | |
@@ -195,37 +236,11 @@ private static String genObject(Class clazz, String cacheKey) { | |||
| 195 | 236 | current.put(fieldName[fieldName.length - 1], field); | |
| 196 | 237 | } | |
| 197 | 238 | } | |
| 198 | - if (map.isEmpty()) { | ||
| 199 | - StringBuilder lines = new StringBuilder(); | ||
| 200 | - append(lines, "public Object decode(com.jsoniter.Jsoniter iter) {"); | ||
| 201 | - append(lines, "{{clazz}} obj = new {{clazz}}();"); | ||
| 202 | - append(lines, "iter.skip();"); | ||
| 203 | - append(lines, "return obj;"); | ||
| 204 | - append(lines, "}"); | ||
| 205 | - return lines.toString().replace("{{clazz}}", clazz.getName()); | ||
| 206 | - } | ||
| 207 | - StringBuilder lines = new StringBuilder(); | ||
| 208 | - append(lines, "public Object decode(com.jsoniter.Jsoniter iter) {"); | ||
| 209 | - append(lines, "{{clazz}} obj = new {{clazz}}();"); | ||
| 210 | - append(lines, "for (com.jsoniter.Slice field = iter.readObjectAsSlice(); field != null; field = iter.readObjectAsSlice()) {"); | ||
| 211 | - append(lines, "switch (field.len) {"); | ||
| 212 | - for (Map.Entry<Integer, Object> entry : map.entrySet()) { | ||
| 213 | - Integer len = entry.getKey(); | ||
| 214 | - append(lines, "case " + len + ": "); | ||
| 215 | - Map<Byte, Object> current = (Map<Byte, Object>) entry.getValue(); | ||
| 216 | - addFieldDispatch(lines, len, 0, current, cacheKey); | ||
| 217 | - append(lines, "break;"); | ||
| 218 | - } | ||
| 219 | - append(lines, "}"); | ||
| 220 | - append(lines, "iter.skip();"); | ||
| 221 | - append(lines, "}"); | ||
| 222 | - append(lines, "return obj;"); | ||
| 223 | - append(lines, "}"); | ||
| 224 | - return lines.toString().replace("{{clazz}}", clazz.getName()); | ||
| 239 | + return trieTree; | ||
| 225 | 240 | } | |
| 226 | 241 | ||
| 227 | 242 | private static Decoder createFieldDecoder(String fieldCacheKey, Field field) { | |
| 228 | - for (Extension extension : fieldDecoderFactories) { | ||
| 243 | + for (Extension extension : extensions) { | ||
| 229 | 244 | Decoder decoder = extension.createDecoder(field); | |
| 230 | 245 | if (decoder != null) { | |
| 231 | 246 | addNewDecoder(fieldCacheKey, decoder); | |
@@ -480,8 +495,8 @@ private static void append(StringBuilder lines, String str) { | |||
| 480 | 495 | lines.append("\n"); | |
| 481 | 496 | } | |
| 482 | 497 | ||
| 483 | - public static void addFieldDecoderFactory(Extension extension) { | ||
| 484 | - fieldDecoderFactories.add(extension); | ||
| 498 | + public static void registerExtension(Extension extension) { | ||
| 499 | + extensions.add(extension); | ||
| 485 | 500 | } | |
| 486 | 501 | ||
| 487 | 502 | public static Decoder.IntDecoder getIntDecoder(String cacheKey) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,7 @@ | |||
| 1 | 1 | package com.jsoniter; | |
| 2 | 2 | ||
| 3 | 3 | import java.lang.reflect.Field; | |
| 4 | + import java.lang.reflect.Type; | ||
| 4 | 5 | ||
| 5 | 6 | public class EmptyExtension implements Extension { | |
| 6 | 7 | ||
@@ -13,4 +14,9 @@ public Decoder createDecoder(Field field) { | |||
| 13 | 14 | public String[] getAlternativeFieldNames(Field field) { | |
| 14 | 15 | return null; | |
| 15 | 16 | } | |
| 17 | + | ||
| 18 | + @Override | ||
| 19 | + public String codegenNewInstance(Type type) { | ||
| 20 | + return null; | ||
| 21 | + } | ||
| 16 | 22 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,7 @@ | |||
| 1 | 1 | package com.jsoniter; | |
| 2 | 2 | ||
| 3 | 3 | import java.lang.reflect.Field; | |
| 4 | + import java.lang.reflect.Type; | ||
| 4 | 5 | ||
| 5 | 6 | public interface Extension { | |
| 6 | 7 | /** | |
@@ -13,8 +14,17 @@ public interface Extension { | |||
| 13 | 14 | ||
| 14 | 15 | /** | |
| 15 | 16 | * Customize the field map to | |
| 17 | + * | ||
| 16 | 18 | * @param field the field reflection object | |
| 17 | 19 | * @return null, if fallback to default behavior | |
| 18 | 20 | */ | |
| 19 | 21 | String[] getAlternativeFieldNames(Field field); | |
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * Generate source code for creating new instance | ||
| 25 | + * | ||
| 26 | + * @param type the type of new object to create | ||
| 27 | + * @return generated source code | ||
| 28 | + */ | ||
| 29 | + String codegenNewInstance(Type type); | ||
| 20 | 30 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1033,7 +1033,7 @@ public static void clearDecoders() { | |||
| 1033 | 1033 | Codegen.cache.clear(); | |
| 1034 | 1034 | } | |
| 1035 | 1035 | ||
| 1036 | - public static void registerFieldDecoderFactory(Extension extension) { | ||
| 1037 | - Codegen.addFieldDecoderFactory(extension); | ||
| 1036 | + public static void registerExtension(Extension extension) { | ||
| 1037 | + Codegen.registerExtension(extension); | ||
| 1038 | 1038 | } | |
| 1039 | 1039 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,20 +1,14 @@ | |||
| 1 | 1 | package com.jsoniter.annotation.jsoniter; | |
| 2 | 2 | ||
| 3 | - import com.jsoniter.Decoder; | ||
| 4 | - import com.jsoniter.Extension; | ||
| 3 | + import com.jsoniter.EmptyExtension; | ||
| 5 | 4 | import com.jsoniter.Jsoniter; | |
| 6 | 5 | ||
| 7 | 6 | import java.lang.reflect.Field; | |
| 8 | 7 | ||
| 9 | - public class JsoniterAnnotationSupport implements Extension { | ||
| 8 | + public class JsoniterAnnotationSupport extends EmptyExtension { | ||
| 10 | 9 | ||
| 11 | 10 | public static void enable() { | |
| 12 | - Jsoniter.registerFieldDecoderFactory(new JsoniterAnnotationSupport()); | ||
| 13 | - } | ||
| 14 | - | ||
| 15 | - @Override | ||
| 16 | - public Decoder createDecoder(final Field field) { | ||
| 17 | - return null; | ||
| 11 | + Jsoniter.registerExtension(new JsoniterAnnotationSupport()); | ||
| 18 | 12 | } | |
| 19 | 13 | ||
| 20 | 14 | @Override | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | 5 | import java.io.IOException; | |
| 6 | 6 | import java.lang.reflect.Field; | |
| 7 | + import java.lang.reflect.Type; | ||
| 7 | 8 | import java.util.Date; | |
| 8 | 9 | ||
| 9 | 10 | public class TestCustomize extends TestCase { | |
@@ -33,7 +34,7 @@ public Object decode(Jsoniter iter) throws IOException { | |||
| 33 | 34 | } | |
| 34 | 35 | ||
| 35 | 36 | public void test_customize_all_fields() throws IOException { | |
| 36 | - Jsoniter.registerFieldDecoderFactory(new Extension() { | ||
| 37 | + Jsoniter.registerExtension(new EmptyExtension() { | ||
| 37 | 38 | @Override | |
| 38 | 39 | public Decoder createDecoder(Field field) { | |
| 39 | 40 | if (field.getDeclaringClass() == CustomizedObject.class && field.getName().equals("field1")) { | |
@@ -47,19 +48,14 @@ public Object decode(Jsoniter iter) throws IOException { | |||
| 47 | 48 | } | |
| 48 | 49 | return null; | |
| 49 | 50 | } | |
| 50 | - | ||
| 51 | - @Override | ||
| 52 | - public String[] getAlternativeFieldNames(Field field) { | ||
| 53 | - return null; | ||
| 54 | - } | ||
| 55 | 51 | }); | |
| 56 | 52 | Jsoniter iter = Jsoniter.parse("{'field1': 100}".replace('\'', '"')); | |
| 57 | 53 | CustomizedObject myObject = iter.read(CustomizedObject.class); | |
| 58 | 54 | assertEquals("100", myObject.field1); | |
| 59 | 55 | } | |
| 60 | 56 | ||
| 61 | 57 | public void test_change_field_name() throws IOException { | |
| 62 | - Jsoniter.registerFieldDecoderFactory(new Extension() { | ||
| 58 | + Jsoniter.registerExtension(new EmptyExtension() { | ||
| 63 | 59 | @Override | |
| 64 | 60 | public Decoder createDecoder(Field field) { | |
| 65 | 61 | if (field.getDeclaringClass() == CustomizedObject.class && field.getName().equals("field1")) { | |
@@ -107,7 +103,16 @@ public Object decode(Jsoniter iter) throws IOException { | |||
| 107 | 103 | } | |
| 108 | 104 | ||
| 109 | 105 | public void test_customized_constructor() throws IOException { | |
| 110 | - Jsoniter iter = Jsoniter.parse("{'field1': 100}".replace('\'', '"')); | ||
| 106 | + Jsoniter.registerExtension(new EmptyExtension(){ | ||
| 107 | + @Override | ||
| 108 | + public String codegenNewInstance(Type type) { | ||
| 109 | + if (type == CtorCustomizedObject.class) { | ||
| 110 | + return "new " + CtorCustomizedObject.class.getName() + "(iter.readInt())"; | ||
| 111 | + } | ||
| 112 | + return null; | ||
| 113 | + } | ||
| 114 | + }); | ||
| 115 | + Jsoniter iter = Jsoniter.parse("100".replace('\'', '"')); | ||
| 111 | 116 | CtorCustomizedObject myObject = iter.read(CtorCustomizedObject.class); | |
| 112 | 117 | assertEquals(100, myObject.getField1()); | |
| 113 | 118 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments