org.chromium.sdk/src/org/chromium/sdk/internal/protocolparser/dynamicimpl/JsonProtocolParser.java
changeset 2 e4420d2515f1
child 355 8726e95bcbba
equal deleted inserted replaced
1:ef76fc2ac88c 2:e4420d2515f1
       
     1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
       
     2 // Use of this source code is governed by a BSD-style license that can be
       
     3 // found in the LICENSE file.
       
     4 
       
     5 package org.chromium.sdk.internal.protocolparser.dynamicimpl;
       
     6 
       
     7 import java.lang.annotation.RetentionPolicy;
       
     8 import java.lang.reflect.Method;
       
     9 import java.lang.reflect.ParameterizedType;
       
    10 import java.lang.reflect.Type;
       
    11 import java.lang.reflect.WildcardType;
       
    12 import java.util.ArrayList;
       
    13 import java.util.Arrays;
       
    14 import java.util.Collections;
       
    15 import java.util.HashMap;
       
    16 import java.util.List;
       
    17 import java.util.Map;
       
    18 
       
    19 import org.chromium.sdk.internal.protocolparser.JsonField;
       
    20 import org.chromium.sdk.internal.protocolparser.JsonNullable;
       
    21 import org.chromium.sdk.internal.protocolparser.JsonOptionalField;
       
    22 import org.chromium.sdk.internal.protocolparser.JsonOverrideField;
       
    23 import org.chromium.sdk.internal.protocolparser.JsonProtocolModelParseException;
       
    24 import org.chromium.sdk.internal.protocolparser.JsonProtocolParseException;
       
    25 import org.chromium.sdk.internal.protocolparser.JsonSubtype;
       
    26 import org.chromium.sdk.internal.protocolparser.JsonSubtypeCasting;
       
    27 import org.chromium.sdk.internal.protocolparser.JsonType;
       
    28 import org.json.simple.JSONArray;
       
    29 import org.json.simple.JSONObject;
       
    30 
       
    31 /**
       
    32  * Java dynamic-proxy based parser for set of json types. It uses set of type interfaces
       
    33  * as model description and provides implementations for them. JsonProtocolParser
       
    34  * converts JSONObject into a required Java type instance.
       
    35  */
       
    36 public class JsonProtocolParser {
       
    37   private final Map<Class<?>, TypeHandler<?>> type2TypeHandler;
       
    38 
       
    39   /**
       
    40    * Constructs parser from a set of type interfaces.
       
    41    */
       
    42   public JsonProtocolParser(Class<?> ... protocolInterfaces)
       
    43       throws JsonProtocolModelParseException {
       
    44     this(Arrays.asList(protocolInterfaces), Collections.<JsonProtocolParser>emptyList());
       
    45   }
       
    46 
       
    47   /**
       
    48    * Constructs parser from a set of type interfaces and a list of base packages. Type interfaces
       
    49    * may reference to type interfaces from base packages.
       
    50    * @param basePackages list of base packages in form of list of {@link JsonProtocolParser}'s
       
    51    */
       
    52   public JsonProtocolParser(List<? extends Class<?>> protocolInterfaces,
       
    53       List<? extends JsonProtocolParser> basePackages) throws JsonProtocolModelParseException {
       
    54     type2TypeHandler = readTypes(protocolInterfaces, basePackages);
       
    55   }
       
    56 
       
    57   /**
       
    58    * Parses {@link JSONObject} as typeClass type.
       
    59    */
       
    60   public <T> T parse(JSONObject object, Class<T> typeClass) throws JsonProtocolParseException {
       
    61     return parseAnything(object, typeClass);
       
    62   }
       
    63 
       
    64   /**
       
    65    * Parses any object as typeClass type. Non-JSONObject only makes sense for
       
    66    * types with {@link JsonType#subtypesChosenManually()} = true annotation.
       
    67    */
       
    68   public <T> T parseAnything(Object object, Class<T> typeClass) throws JsonProtocolParseException {
       
    69     TypeHandler<T> type = type2TypeHandler.get(typeClass).cast(typeClass);
       
    70     return type.parseRoot(object);
       
    71   }
       
    72 
       
    73   private static Map<Class<?>, TypeHandler<?>> readTypes(
       
    74       List<? extends Class<?>> protocolInterfaces,
       
    75       final List<? extends JsonProtocolParser> basePackages)
       
    76       throws JsonProtocolModelParseException {
       
    77     ReadInterfacesSession session = new ReadInterfacesSession(protocolInterfaces, basePackages);
       
    78     session.go();
       
    79     return session.getResult();
       
    80   }
       
    81 
       
    82 
       
    83   private static class ReadInterfacesSession {
       
    84     private final Map<Class<?>, TypeHandler<?>> type2typeHandler;
       
    85     private final List<? extends JsonProtocolParser> basePackages;
       
    86 
       
    87     final List<RefImpl<?>> refs = new ArrayList<RefImpl<?>>();
       
    88     final List<SubtypeCaster> subtypeCasters =
       
    89         new ArrayList<SubtypeCaster>();
       
    90 
       
    91     ReadInterfacesSession(List<? extends Class<?>> protocolInterfaces,
       
    92         List<? extends JsonProtocolParser> basePackages) {
       
    93       this.type2typeHandler = new HashMap<Class<?>, TypeHandler<?>>();
       
    94       this.basePackages = basePackages;
       
    95 
       
    96       for (Class<?> typeClass : protocolInterfaces) {
       
    97         type2typeHandler.put(typeClass, null);
       
    98       }
       
    99     }
       
   100 
       
   101     void go() throws JsonProtocolModelParseException {
       
   102       // Create TypeHandler's.
       
   103       for (Class<?> typeClass : type2typeHandler.keySet()) {
       
   104         TypeHandler<?> typeHandler = createTypeHandler(typeClass);
       
   105         type2typeHandler.put(typeClass, typeHandler);
       
   106       }
       
   107 
       
   108       // Resolve cross-references.
       
   109       for (RefImpl<?> ref : refs) {
       
   110         TypeHandler<?> type = type2typeHandler.get(ref.typeClass);
       
   111         if (type == null) {
       
   112           throw new RuntimeException();
       
   113         }
       
   114         ref.set(type);
       
   115       }
       
   116 
       
   117       // Set subtype casters.
       
   118       for (SubtypeCaster subtypeCaster : subtypeCasters) {
       
   119         TypeHandler<?> subtypeHandler = subtypeCaster.getSubtypeHandler();
       
   120         subtypeHandler.getSubtypeSupport().setSubtypeCaster(subtypeCaster);
       
   121       }
       
   122 
       
   123       // Check subtype casters consistency.
       
   124       for (TypeHandler<?> type : type2typeHandler.values()) {
       
   125         type.getSubtypeSupport().checkHasSubtypeCaster();
       
   126       }
       
   127     }
       
   128 
       
   129     Map<Class<?>, TypeHandler<?>> getResult() {
       
   130       return type2typeHandler;
       
   131     }
       
   132 
       
   133     private <T> TypeHandler<T> createTypeHandler(Class<T> typeClass)
       
   134         throws JsonProtocolModelParseException {
       
   135       if (!typeClass.isInterface()) {
       
   136         throw new JsonProtocolModelParseException("Json model type should be interface: " +
       
   137             typeClass.getName());
       
   138       }
       
   139 
       
   140       FieldProcessor<T> fields = new FieldProcessor<T>(typeClass);
       
   141 
       
   142       fields.go();
       
   143 
       
   144       Map<Method, MethodHandler> methodHandlerMap = fields.getMethodHandlerMap();
       
   145       methodHandlerMap.putAll(BaseHandlersLibrary.INSTANCE.getAllHandlers());
       
   146 
       
   147       TypeHandler.EagerFieldParser eagerFieldParser =
       
   148           new EagerFieldParserImpl(fields.getOnDemandHanlers());
       
   149 
       
   150       RefToType<?> superclassRef = getSuperclassRef(typeClass);
       
   151 
       
   152       return new TypeHandler<T>(typeClass, superclassRef,
       
   153           fields.getFieldArraySize(), methodHandlerMap, fields.getFieldLoaders(),
       
   154           fields.getFieldConditions(), eagerFieldParser, fields.getAlgCasesData());
       
   155     }
       
   156 
       
   157     private SlowParser<?> getFieldTypeParser(Type type, boolean declaredNullable,
       
   158         boolean isSubtyping) throws JsonProtocolModelParseException {
       
   159       if (type instanceof Class) {
       
   160         Class<?> typeClass = (Class<?>) type;
       
   161         if (type == Long.class) {
       
   162           nullableIsNotSupported(declaredNullable);
       
   163           return LONG_PARSER.getNullable();
       
   164         } else if (type == Long.TYPE) {
       
   165           nullableIsNotSupported(declaredNullable);
       
   166           return LONG_PARSER.getNotNullable();
       
   167         } else if (type == Boolean.class) {
       
   168           nullableIsNotSupported(declaredNullable);
       
   169           return BOOLEAN_PARSER.getNullable();
       
   170         } else if (type == Boolean.TYPE) {
       
   171           nullableIsNotSupported(declaredNullable);
       
   172           return BOOLEAN_PARSER.getNotNullable();
       
   173         } else if (type == Void.class) {
       
   174           nullableIsNotSupported(declaredNullable);
       
   175           return VOID_PARSER;
       
   176         } else if (type == String.class) {
       
   177           return STRING_PARSER.get(declaredNullable);
       
   178         } else if (type == Object.class) {
       
   179           return OBJECT_PARSER.get(declaredNullable);
       
   180         } else if (type == JSONObject.class) {
       
   181           return JSON_PARSER.get(declaredNullable);
       
   182         } else if (typeClass.isEnum()) {
       
   183           Class<RetentionPolicy> enumTypeClass = (Class<RetentionPolicy>) typeClass;
       
   184           return EnumParser.create(enumTypeClass, declaredNullable);
       
   185         } else if (type2typeHandler.containsKey(typeClass)) {
       
   186         }
       
   187         RefToType<?> ref = getTypeRef(typeClass);
       
   188         if (ref != null) {
       
   189           return createJsonParser(ref, declaredNullable, isSubtyping);
       
   190         }
       
   191         throw new JsonProtocolModelParseException("Method return type " + type +
       
   192             " (simple class) not supported");
       
   193       } else if (type instanceof ParameterizedType) {
       
   194         ParameterizedType parameterizedType = (ParameterizedType) type;
       
   195         if (parameterizedType.getRawType() == List.class) {
       
   196           Type argumentType = parameterizedType.getActualTypeArguments()[0];
       
   197           if (argumentType instanceof WildcardType) {
       
   198             WildcardType wildcard = (WildcardType) argumentType;
       
   199             if (wildcard.getLowerBounds().length == 0 && wildcard.getUpperBounds().length == 1) {
       
   200               argumentType = wildcard.getUpperBounds()[0];
       
   201             }
       
   202           }
       
   203           SlowParser<?> componentParser = getFieldTypeParser(argumentType, false, false);
       
   204           return createArrayParser(componentParser, declaredNullable);
       
   205         } else {
       
   206           throw new JsonProtocolModelParseException("Method return type " + type +
       
   207               " (generic) not supported");
       
   208         }
       
   209       } else {
       
   210         throw new JsonProtocolModelParseException("Method return type " + type + " not supported");
       
   211       }
       
   212     }
       
   213 
       
   214     private void nullableIsNotSupported(boolean declaredNullable)
       
   215         throws JsonProtocolModelParseException {
       
   216       if (declaredNullable) {
       
   217         throw new JsonProtocolModelParseException("The type cannot be declared nullable");
       
   218       }
       
   219     }
       
   220 
       
   221     private <T> JsonTypeParser<T> createJsonParser(RefToType<T> type, boolean isNullable,
       
   222         boolean isSubtyping) {
       
   223       return new JsonTypeParser<T>(type, isNullable, isSubtyping);
       
   224     }
       
   225 
       
   226     private <T> ArrayParser<T> createArrayParser(SlowParser<T> componentParser,
       
   227         boolean isNullable) {
       
   228       return new ArrayParser<T>(componentParser, isNullable);
       
   229     }
       
   230 
       
   231     private <T> RefToType<T> getTypeRef(final Class<T> typeClass) {
       
   232       if (type2typeHandler.containsKey(typeClass)) {
       
   233         RefImpl<T> result = new RefImpl<T>(typeClass);
       
   234         refs.add(result);
       
   235         return result;
       
   236       }
       
   237       for (JsonProtocolParser baseParser : basePackages) {
       
   238         TypeHandler<?> typeHandler = baseParser.type2TypeHandler.get(typeClass);
       
   239         if (typeHandler != null) {
       
   240           final TypeHandler<T> typeHandlerT = (TypeHandler<T>) typeHandler;
       
   241           return new RefToType<T>() {
       
   242             @Override
       
   243             TypeHandler<T> get() {
       
   244               return typeHandlerT;
       
   245             }
       
   246             @Override
       
   247             Class<?> getTypeClass() {
       
   248               return typeClass;
       
   249             }
       
   250           };
       
   251         }
       
   252       }
       
   253       return null;
       
   254     }
       
   255 
       
   256     private RefToType<?> getSuperclassRef(Class<?> typeClass)
       
   257         throws JsonProtocolModelParseException {
       
   258       RefToType<?> result = null;
       
   259       for (Type interfc : typeClass.getGenericInterfaces()) {
       
   260         if (interfc instanceof ParameterizedType == false) {
       
   261           continue;
       
   262         }
       
   263         ParameterizedType parameterizedType = (ParameterizedType) interfc;
       
   264         if (parameterizedType.getRawType() != JsonSubtype.class) {
       
   265           continue;
       
   266         }
       
   267         Type param = parameterizedType.getActualTypeArguments()[0];
       
   268         if (param instanceof Class == false) {
       
   269           throw new JsonProtocolModelParseException("Unexpected type of superclass " + param);
       
   270         }
       
   271         Class<?> paramClass = (Class<?>) param;
       
   272         if (result != null) {
       
   273           throw new JsonProtocolModelParseException("Already has superclass " +
       
   274               result.getTypeClass().getName());
       
   275         }
       
   276         result = getTypeRef(paramClass);
       
   277         if (result == null) {
       
   278           throw new JsonProtocolModelParseException("Unknown base class " + paramClass.getName());
       
   279         }
       
   280       }
       
   281       return result;
       
   282     }
       
   283 
       
   284     class FieldProcessor<T> {
       
   285       private final Class<T> typeClass;
       
   286 
       
   287       private final JsonType jsonTypeAnn;
       
   288       private final List<FieldLoader> fieldLoaders = new ArrayList<FieldLoader>(2);
       
   289       private final List<LazyParseFieldMethodHandler> onDemandHanlers =
       
   290           new ArrayList<LazyParseFieldMethodHandler>();
       
   291       private final Map<Method, MethodHandler> methodHandlerMap =
       
   292           new HashMap<Method, MethodHandler>();
       
   293       private final FieldMap fieldMap = new FieldMap();
       
   294       private final List<FieldCondition> fieldConditions = new ArrayList<FieldCondition>(2);
       
   295       private AlgebraicCasesDataImpl algCasesData = null;
       
   296       private int fieldArraySize = 0;
       
   297 
       
   298       FieldProcessor(Class<T> typeClass) throws JsonProtocolModelParseException {
       
   299         this.typeClass = typeClass;
       
   300         jsonTypeAnn = typeClass.getAnnotation(JsonType.class);
       
   301         if (jsonTypeAnn == null) {
       
   302           throw new JsonProtocolModelParseException("Not a json model type: " + typeClass);
       
   303         }
       
   304       }
       
   305 
       
   306       void go() throws JsonProtocolModelParseException {
       
   307         for (Method m : typeClass.getDeclaredMethods()) {
       
   308           try {
       
   309             processMethod(m);
       
   310           } catch (JsonProtocolModelParseException e) {
       
   311             throw new JsonProtocolModelParseException("Problem with method " + m, e);
       
   312           }
       
   313         }
       
   314       }
       
   315 
       
   316       private void processMethod(Method m) throws JsonProtocolModelParseException {
       
   317         if (m.getParameterTypes().length != 0) {
       
   318           throw new JsonProtocolModelParseException("No parameters expected in " + m);
       
   319         }
       
   320         JsonOverrideField overrideFieldAnn = m.getAnnotation(JsonOverrideField.class);
       
   321         FieldConditionLogic fieldConditionLogic = FieldConditionLogic.readLogic(m);
       
   322         String fieldName = checkAndGetJsonFieldName(m);
       
   323         MethodHandler methodHandler;
       
   324 
       
   325         JsonSubtypeCasting jsonSubtypeCaseAnn = m.getAnnotation(JsonSubtypeCasting.class);
       
   326         if (jsonSubtypeCaseAnn != null) {
       
   327           if (fieldConditionLogic != null) {
       
   328             throw new JsonProtocolModelParseException(
       
   329                 "Subtype condition annotation only works with field getter methods");
       
   330           }
       
   331           if (overrideFieldAnn != null) {
       
   332             throw new JsonProtocolModelParseException(
       
   333                 "Override annotation only works with field getter methods");
       
   334           }
       
   335           if (algCasesData == null) {
       
   336             algCasesData = new AlgebraicCasesDataImpl(jsonTypeAnn.subtypesChosenManually());
       
   337           }
       
   338 
       
   339           if (jsonTypeAnn.subtypesChosenManually()) {
       
   340             methodHandler = processManualSubtypeMethod(m, jsonSubtypeCaseAnn);
       
   341           } else {
       
   342             if (jsonSubtypeCaseAnn.reinterpret()) {
       
   343               throw new JsonProtocolModelParseException(
       
   344                   "Option 'reinterpret' is only available with 'subtypes chosen manually'");
       
   345             }
       
   346             methodHandler = processAutomaticSubtypeMethod(m);
       
   347           }
       
   348 
       
   349         } else {
       
   350           methodHandler = processFieldGetterMethod(m, fieldConditionLogic, overrideFieldAnn,
       
   351               fieldName);
       
   352         }
       
   353         methodHandlerMap.put(m, methodHandler);
       
   354       }
       
   355 
       
   356       private MethodHandler processFieldGetterMethod(Method m,
       
   357           FieldConditionLogic fieldConditionLogic, JsonOverrideField overrideFieldAnn,
       
   358           String fieldName) throws JsonProtocolModelParseException {
       
   359         MethodHandler methodHandler;
       
   360         JsonNullable nullableAnn = m.getAnnotation(JsonNullable.class);
       
   361         SlowParser<?> fieldTypeParser = getFieldTypeParser(m.getGenericReturnType(),
       
   362             nullableAnn != null, false);
       
   363         if (fieldConditionLogic != null) {
       
   364           fieldConditions.add(new FieldCondition(fieldName, fieldTypeParser.asQuickParser(),
       
   365               fieldConditionLogic));
       
   366         }
       
   367         if (overrideFieldAnn == null) {
       
   368           fieldMap.localNames.add(fieldName);
       
   369         } else {
       
   370           fieldMap.overridenNames.add(fieldName);
       
   371         }
       
   372 
       
   373         boolean isOptional = isOptionalField(m);
       
   374 
       
   375         if (fieldTypeParser.asQuickParser() != null) {
       
   376           LazyParseFieldMethodHandler onDemandHandler = new LazyParseFieldMethodHandler(
       
   377               fieldTypeParser.asQuickParser(), isOptional, fieldName);
       
   378           onDemandHanlers.add(onDemandHandler);
       
   379           methodHandler = onDemandHandler;
       
   380         } else {
       
   381           int fieldCode = allocateFieldInArray();
       
   382           FieldLoader fieldLoader = new FieldLoader(fieldCode, fieldName, fieldTypeParser,
       
   383               isOptional);
       
   384           fieldLoaders.add(fieldLoader);
       
   385           methodHandler = new PreparsedFieldMethodHandler(fieldCode,
       
   386               fieldTypeParser.getValueFinisher());
       
   387         }
       
   388         return methodHandler;
       
   389       }
       
   390 
       
   391       private MethodHandler processAutomaticSubtypeMethod(Method m)
       
   392           throws JsonProtocolModelParseException {
       
   393         MethodHandler methodHandler;
       
   394         if (m.getReturnType() == Void.TYPE) {
       
   395           if (algCasesData.hasDefaultCase) {
       
   396             throw new JsonProtocolModelParseException("Duplicate default case method: " + m);
       
   397           }
       
   398           algCasesData.hasDefaultCase = true;
       
   399           methodHandler = RETURN_NULL_METHOD_HANDLER;
       
   400         } else {
       
   401           Class<?> methodType = m.getReturnType();
       
   402           RefToType<?> ref = getTypeRef(methodType);
       
   403           if (ref == null) {
       
   404             throw new JsonProtocolModelParseException("Unknown return type in " + m);
       
   405           }
       
   406           if (algCasesData.variantCodeFieldPos == -1) {
       
   407             algCasesData.variantCodeFieldPos = allocateFieldInArray();
       
   408             algCasesData.variantValueFieldPos = allocateFieldInArray();
       
   409           }
       
   410           int algCode = algCasesData.subtypes.size();
       
   411           algCasesData.subtypes.add(ref);
       
   412           final AutoSubtypeMethodHandler algMethodHandler = new AutoSubtypeMethodHandler(
       
   413               algCasesData.variantCodeFieldPos, algCasesData.variantValueFieldPos,
       
   414               algCode);
       
   415           methodHandler = algMethodHandler;
       
   416 
       
   417           SubtypeCaster subtypeCaster = new SubtypeCaster(typeClass, ref) {
       
   418             @Override
       
   419             ObjectData getSubtypeObjectData(ObjectData objectData) {
       
   420               return algMethodHandler.getFieldObjectData(objectData);
       
   421             }
       
   422           };
       
   423 
       
   424           subtypeCasters.add(subtypeCaster);
       
   425         }
       
   426         return methodHandler;
       
   427       }
       
   428 
       
   429 
       
   430       private MethodHandler processManualSubtypeMethod(Method m,
       
   431           JsonSubtypeCasting jsonSubtypeCaseAnn) throws JsonProtocolModelParseException {
       
   432         int fieldCode = allocateFieldInArray();
       
   433 
       
   434         SlowParser<?> fieldTypeParser = getFieldTypeParser(m.getGenericReturnType(), false,
       
   435             !jsonSubtypeCaseAnn.reinterpret());
       
   436 
       
   437         if (!Arrays.asList(m.getExceptionTypes()).contains(JsonProtocolParseException.class)) {
       
   438           throw new JsonProtocolModelParseException(
       
   439               "Method should declare JsonProtocolParseException exception: " + m);
       
   440         }
       
   441 
       
   442         final ManualSubtypeMethodHandler handler = new ManualSubtypeMethodHandler(fieldCode,
       
   443             fieldTypeParser);
       
   444         JsonTypeParser<?> parserAsJsonTypeParser = fieldTypeParser.asJsonTypeParser();
       
   445         if (parserAsJsonTypeParser != null && parserAsJsonTypeParser.isSubtyping()) {
       
   446           SubtypeCaster subtypeCaster = new SubtypeCaster(typeClass,
       
   447               parserAsJsonTypeParser.getType()) {
       
   448             @Override
       
   449             ObjectData getSubtypeObjectData(ObjectData baseObjectData)
       
   450                 throws JsonProtocolParseException {
       
   451               ObjectData objectData = baseObjectData;
       
   452               return handler.getSubtypeData(objectData);
       
   453             }
       
   454           };
       
   455           subtypeCasters.add(subtypeCaster);
       
   456         }
       
   457         return handler;
       
   458       }
       
   459 
       
   460       int getFieldArraySize() {
       
   461         return fieldArraySize;
       
   462       }
       
   463 
       
   464       void setFieldArraySize(int fieldArraySize) {
       
   465         this.fieldArraySize = fieldArraySize;
       
   466       }
       
   467 
       
   468       AlgebraicCasesDataImpl getAlgCasesData() {
       
   469         return algCasesData;
       
   470       }
       
   471 
       
   472       void setAlgCasesData(AlgebraicCasesDataImpl algCasesData) {
       
   473         this.algCasesData = algCasesData;
       
   474       }
       
   475 
       
   476       List<FieldLoader> getFieldLoaders() {
       
   477         return fieldLoaders;
       
   478       }
       
   479 
       
   480       List<LazyParseFieldMethodHandler> getOnDemandHanlers() {
       
   481         return onDemandHanlers;
       
   482       }
       
   483 
       
   484       Map<Method, MethodHandler> getMethodHandlerMap() {
       
   485         return methodHandlerMap;
       
   486       }
       
   487 
       
   488       List<FieldCondition> getFieldConditions() {
       
   489         return fieldConditions;
       
   490       }
       
   491 
       
   492       private int allocateFieldInArray() {
       
   493         return fieldArraySize++;
       
   494       }
       
   495 
       
   496       private boolean isOptionalField(Method m) {
       
   497         JsonOptionalField jsonOptionalFieldAnn = m.getAnnotation(JsonOptionalField.class);
       
   498         return jsonOptionalFieldAnn != null;
       
   499       }
       
   500 
       
   501       private String checkAndGetJsonFieldName(Method m) throws JsonProtocolModelParseException {
       
   502         if (m.getParameterTypes().length != 0) {
       
   503           throw new JsonProtocolModelParseException("Must have 0 parameters");
       
   504         }
       
   505         JsonField fieldAnn = m.getAnnotation(JsonField.class);
       
   506         if (fieldAnn != null) {
       
   507           return fieldAnn.jsonLiteralName();
       
   508         }
       
   509         String name = m.getName();
       
   510         if (name.startsWith("get") && name.length() > 3) {
       
   511           name = Character.toLowerCase(name.charAt(3)) + name.substring(4);
       
   512         }
       
   513         return name;
       
   514       }
       
   515     }
       
   516   }
       
   517 
       
   518   private static class EagerFieldParserImpl extends TypeHandler.EagerFieldParser {
       
   519     private final List<LazyParseFieldMethodHandler> onDemandHandlers;
       
   520 
       
   521     private EagerFieldParserImpl(List<LazyParseFieldMethodHandler> onDemandHandlers) {
       
   522       this.onDemandHandlers = onDemandHandlers;
       
   523     }
       
   524 
       
   525     @Override
       
   526     void parseAllFields(ObjectData objectData) throws JsonProtocolParseException {
       
   527       for (LazyParseFieldMethodHandler handler : onDemandHandlers) {
       
   528         handler.parse(objectData);
       
   529       }
       
   530     }
       
   531   }
       
   532 
       
   533   private static class LazyParseFieldMethodHandler extends MethodHandler {
       
   534     private final QuickParser<?> quickParser;
       
   535     private final boolean isOptional;
       
   536     private final String fieldName;
       
   537 
       
   538     LazyParseFieldMethodHandler(QuickParser<?> quickParser, boolean isOptional, String fieldName) {
       
   539       this.quickParser = quickParser;
       
   540       this.isOptional = isOptional;
       
   541       this.fieldName = fieldName;
       
   542     }
       
   543 
       
   544     @Override
       
   545     Object handle(Object myself, ObjectData objectData, Object[] args) {
       
   546       try {
       
   547         return parse(objectData);
       
   548       } catch (JsonProtocolParseException e) {
       
   549         throw new JsonProtocolParseRuntimeException("On demand parsing failed", e);
       
   550       }
       
   551     }
       
   552 
       
   553     public Object parse(ObjectData objectData) throws JsonProtocolParseException {
       
   554       Map<?,?> properties = (JSONObject)objectData.getUnderlyingObject();
       
   555       Object value = properties.get(fieldName);
       
   556       boolean hasValue;
       
   557       if (value == null) {
       
   558         hasValue = properties.containsKey(fieldName);
       
   559       } else {
       
   560         hasValue = true;
       
   561       }
       
   562       return parse(hasValue, value, objectData);
       
   563     }
       
   564 
       
   565     public Object parse(boolean hasValue, Object value, ObjectData objectData)
       
   566         throws JsonProtocolParseException {
       
   567       if (hasValue) {
       
   568         try {
       
   569           return quickParser.parseValueQuick(value);
       
   570         } catch (JsonProtocolParseException e) {
       
   571           throw new JsonProtocolParseException("Failed to parse field " + fieldName, e);
       
   572         }
       
   573       } else {
       
   574         if (!isOptional) {
       
   575           throw new JsonProtocolParseException("Field is not optional: " + fieldName);
       
   576         }
       
   577         return null;
       
   578       }
       
   579     }
       
   580   }
       
   581 
       
   582   private static class PreparsedFieldMethodHandler extends MethodHandler {
       
   583     private final int pos;
       
   584     private final FieldLoadedFinisher valueFinisher;
       
   585 
       
   586     PreparsedFieldMethodHandler(int pos, FieldLoadedFinisher valueFinisher) {
       
   587       this.pos = pos;
       
   588       this.valueFinisher = valueFinisher;
       
   589     }
       
   590 
       
   591     @Override
       
   592     Object handle(Object myself, ObjectData objectData, Object[] args) throws Throwable {
       
   593       Object val = objectData.getFieldArray()[pos];
       
   594       if (valueFinisher != null) {
       
   595         val = valueFinisher.getValueForUser(val);
       
   596       }
       
   597       return val;
       
   598     }
       
   599   }
       
   600 
       
   601   static SlowParser<Void> VOID_PARSER = new QuickParser<Void>() {
       
   602     @Override
       
   603     public Void parseValueQuick(Object value) {
       
   604       return null;
       
   605     }
       
   606   };
       
   607 
       
   608   static class SimpleCastParser<T> extends QuickParser<T> {
       
   609     private final boolean nullable;
       
   610     private final Class<T> fieldType;
       
   611 
       
   612     SimpleCastParser(Class<T> fieldType, boolean nullable) {
       
   613       this.fieldType = fieldType;
       
   614       this.nullable = nullable;
       
   615     }
       
   616 
       
   617     @Override
       
   618     public T parseValueQuick(Object value) throws JsonProtocolParseException {
       
   619       if (value == null) {
       
   620         if (nullable) {
       
   621           return null;
       
   622         } else {
       
   623           throw new JsonProtocolParseException("Field must have type " + fieldType.getName());
       
   624         }
       
   625       }
       
   626       try {
       
   627         return fieldType.cast(value);
       
   628       } catch (ClassCastException e) {
       
   629         throw new JsonProtocolParseException("Field must have type " + fieldType.getName(), e);
       
   630       }
       
   631     }
       
   632 
       
   633     @Override
       
   634     public FieldLoadedFinisher getValueFinisher() {
       
   635       return null;
       
   636     }
       
   637   }
       
   638   static class SimpleParserPair<T> {
       
   639     static <T> SimpleParserPair<T> create(Class<T> fieldType) {
       
   640       return new SimpleParserPair<T>(fieldType);
       
   641     }
       
   642 
       
   643     private final SimpleCastParser<T> nullable;
       
   644     private final SimpleCastParser<T> notNullable;
       
   645 
       
   646     private SimpleParserPair(Class<T> fieldType) {
       
   647       nullable = new SimpleCastParser<T>(fieldType, true);
       
   648       notNullable = new SimpleCastParser<T>(fieldType, false);
       
   649     }
       
   650 
       
   651     SimpleCastParser<T> getNullable() {
       
   652       return nullable;
       
   653     }
       
   654 
       
   655     SimpleCastParser<T> getNotNullable() {
       
   656       return notNullable;
       
   657     }
       
   658 
       
   659     SlowParser<?> get(boolean declaredNullable) {
       
   660       return declaredNullable ? nullable : notNullable;
       
   661     }
       
   662   }
       
   663 
       
   664   private static SimpleParserPair<Long> LONG_PARSER = SimpleParserPair.create(Long.class);
       
   665   private static SimpleParserPair<Boolean> BOOLEAN_PARSER = SimpleParserPair.create(Boolean.class);
       
   666   private static SimpleParserPair<String> STRING_PARSER = SimpleParserPair.create(String.class);
       
   667   private static SimpleParserPair<Object> OBJECT_PARSER = SimpleParserPair.create(Object.class);
       
   668   private static SimpleParserPair<JSONObject> JSON_PARSER =
       
   669       SimpleParserPair.create(JSONObject.class);
       
   670 
       
   671   static class ArrayParser<T> extends SlowParser<List<? extends T>> {
       
   672     private final SlowParser<T> componentParser;
       
   673     private final boolean isNullable;
       
   674 
       
   675     ArrayParser(SlowParser<T> componentParser, boolean isNullable) {
       
   676       this.componentParser = componentParser;
       
   677       this.isNullable = isNullable;
       
   678     }
       
   679 
       
   680     @Override
       
   681     public List<? extends T> parseValue(Object value, ObjectData thisData)
       
   682         throws JsonProtocolParseException {
       
   683       if (isNullable && value == null) {
       
   684         return null;
       
   685       }
       
   686       if (value instanceof JSONArray == false) {
       
   687         throw new JsonProtocolParseException("Array value expected");
       
   688       }
       
   689       JSONArray arrayValue = (JSONArray) value;
       
   690       int size = arrayValue.size();
       
   691       List list = new ArrayList<Object>(size);
       
   692       FieldLoadedFinisher valueFinisher = componentParser.getValueFinisher();
       
   693       for (int i = 0; i < size; i++) {
       
   694         // We do not support super object for array component.
       
   695         Object val = componentParser.parseValue(arrayValue.get(i), null);
       
   696         if (valueFinisher != null) {
       
   697           val = valueFinisher.getValueForUser(val);
       
   698         }
       
   699         list.add(val);
       
   700       }
       
   701       return Collections.unmodifiableList(list);
       
   702     }
       
   703     @Override
       
   704     public FieldLoadedFinisher getValueFinisher() {
       
   705       return null;
       
   706     }
       
   707     @Override
       
   708     public JsonTypeParser<?> asJsonTypeParser() {
       
   709       return null;
       
   710     }
       
   711   }
       
   712 
       
   713   static MethodHandler RETURN_NULL_METHOD_HANDLER = new MethodHandler() {
       
   714     @Override
       
   715     Object handle(Object myself, ObjectData objectData, Object[] args) throws Throwable {
       
   716       return null;
       
   717     }
       
   718   };
       
   719 
       
   720   static class AutoSubtypeMethodHandler extends MethodHandler {
       
   721     private final int variantCodeField;
       
   722     private final int variantValueField;
       
   723     private final int code;
       
   724 
       
   725     AutoSubtypeMethodHandler(int variantCodeField, int variantValueField, int code) {
       
   726       this.variantCodeField = variantCodeField;
       
   727       this.variantValueField = variantValueField;
       
   728       this.code = code;
       
   729     }
       
   730 
       
   731     ObjectData getFieldObjectData(ObjectData objectData) {
       
   732       Object[] array = objectData.getFieldArray();
       
   733       Integer actualCode = (Integer) array[variantCodeField];
       
   734       if (this.code == actualCode) {
       
   735         ObjectData data = (ObjectData) array[variantValueField];
       
   736         return data;
       
   737       } else {
       
   738         return null;
       
   739       }
       
   740     }
       
   741 
       
   742     @Override
       
   743     Object handle(Object myself, ObjectData objectData, Object[] args) {
       
   744       ObjectData resData = getFieldObjectData(objectData);
       
   745       if (resData == null) {
       
   746         return null;
       
   747       } else {
       
   748         return resData.getProxy();
       
   749       }
       
   750     }
       
   751   }
       
   752 
       
   753   static class ManualSubtypeMethodHandler extends MethodHandler {
       
   754     private final int fieldPos;
       
   755     private final SlowParser<?> parser;
       
   756 
       
   757     ManualSubtypeMethodHandler(int fieldPos, SlowParser<?> slowParser) {
       
   758       this.fieldPos = fieldPos;
       
   759       this.parser = slowParser;
       
   760     }
       
   761 
       
   762     @Override
       
   763     Object handle(Object myself, ObjectData objectData, Object[] args)
       
   764         throws JsonProtocolParseException {
       
   765       return handle(objectData);
       
   766     }
       
   767 
       
   768     private Object handleRaw(ObjectData objectData) throws JsonProtocolParseException {
       
   769       Object cachedValue = objectData.getFieldArray()[fieldPos];
       
   770       if (cachedValue == null) {
       
   771         cachedValue = parser.parseValue(objectData.getUnderlyingObject(), objectData);
       
   772         objectData.getFieldArray()[fieldPos] = cachedValue;
       
   773       }
       
   774       return cachedValue;
       
   775     }
       
   776 
       
   777     Object handle(ObjectData objectData) throws JsonProtocolParseException {
       
   778       Object res = handleRaw(objectData);
       
   779       FieldLoadedFinisher valueFinisher = parser.getValueFinisher();
       
   780       if (valueFinisher != null) {
       
   781          res = valueFinisher.getValueForUser(res);
       
   782       }
       
   783       return res;
       
   784     }
       
   785 
       
   786     ObjectData getSubtypeData(ObjectData objectData) throws JsonProtocolParseException {
       
   787       return (ObjectData) handleRaw(objectData);
       
   788     }
       
   789   }
       
   790 
       
   791   static class AlgebraicCasesDataImpl extends TypeHandler.AlgebraicCasesData {
       
   792     private int variantCodeFieldPos = -1;
       
   793     private int variantValueFieldPos = -1;
       
   794     private boolean hasDefaultCase = false;
       
   795     private final List<RefToType<?>> subtypes = new ArrayList<RefToType<?>>();
       
   796     private final boolean isManualChoose;
       
   797 
       
   798     AlgebraicCasesDataImpl(boolean isManualChoose) {
       
   799       this.isManualChoose = isManualChoose;
       
   800     }
       
   801 
       
   802     @Override
       
   803     int getVariantCodeFieldPos() {
       
   804       return variantCodeFieldPos;
       
   805     }
       
   806 
       
   807     @Override
       
   808     int getVariantValueFieldPos() {
       
   809       return variantValueFieldPos;
       
   810     }
       
   811 
       
   812     @Override
       
   813     boolean hasDefaultCase() {
       
   814       return hasDefaultCase;
       
   815     }
       
   816 
       
   817     @Override
       
   818     List<RefToType<?>> getSubtypes() {
       
   819       return subtypes;
       
   820     }
       
   821 
       
   822     @Override
       
   823     boolean isManualChoose() {
       
   824       return isManualChoose;
       
   825     }
       
   826   }
       
   827 
       
   828   private static class RefImpl<T> extends RefToType<T> {
       
   829     private final Class<T> typeClass;
       
   830     private TypeHandler<T> type = null;
       
   831 
       
   832     RefImpl(Class<T> typeClass) {
       
   833       this.typeClass = typeClass;
       
   834     }
       
   835 
       
   836     @Override
       
   837     Class<?> getTypeClass() {
       
   838       return typeClass;
       
   839     }
       
   840 
       
   841     @Override
       
   842     TypeHandler<T> get() {
       
   843       return type;
       
   844     }
       
   845 
       
   846     void set(TypeHandler<?> type) {
       
   847       this.type = (TypeHandler<T>)type;
       
   848     }
       
   849   }
       
   850 
       
   851   // We should use it for static analysis later.
       
   852   private static class FieldMap {
       
   853     final List<String> localNames = new ArrayList<String>(5);
       
   854     final List<String> overridenNames = new ArrayList<String>(1);
       
   855   }
       
   856 
       
   857   private static class JsonProtocolParseRuntimeException extends RuntimeException {
       
   858     JsonProtocolParseRuntimeException() {
       
   859     }
       
   860     JsonProtocolParseRuntimeException(String message, Throwable cause) {
       
   861       super(message, cause);
       
   862     }
       
   863     JsonProtocolParseRuntimeException(String message) {
       
   864       super(message);
       
   865     }
       
   866     JsonProtocolParseRuntimeException(Throwable cause) {
       
   867       super(cause);
       
   868     }
       
   869   }
       
   870 }