firefox rdp — initial scopes support
authorVladimir Krivosheev <vladimir.krivosheev@jetbrains.com>
Thu, 8 Jan 2015 14:22:51 +0000 (15:22 +0100)
committerVladimir Krivosheev <vladimir.krivosheev@jetbrains.com>
Thu, 8 Jan 2015 14:22:51 +0000 (15:22 +0100)
35 files changed:
platform/script-debugger/backend/src/org/jetbrains/concurrency/AsyncPromise.java
platform/script-debugger/backend/src/org/jetbrains/concurrency/DonePromise.java
platform/script-debugger/backend/src/org/jetbrains/concurrency/Promise.java
platform/script-debugger/backend/src/org/jetbrains/concurrency/PromiseManager.java
platform/script-debugger/backend/src/org/jetbrains/concurrency/RejectedPromise.java
platform/script-debugger/backend/src/org/jetbrains/debugger/DeclarativeScope.java
platform/script-debugger/backend/src/org/jetbrains/debugger/ObjectScope.java [new file with mode: 0644]
platform/script-debugger/backend/src/org/jetbrains/debugger/Scope.java
platform/script-debugger/backend/src/org/jetbrains/debugger/ScopeBase.java
platform/script-debugger/backend/src/org/jetbrains/debugger/VariablesHost.java [new file with mode: 0644]
platform/script-debugger/backend/src/org/jetbrains/debugger/values/ObjectValue.java
platform/script-debugger/backend/src/org/jetbrains/debugger/values/ObjectValueBase.java
platform/script-debugger/backend/src/org/jetbrains/debugger/values/PrimitiveValue.java
platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.java
platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonField.java
platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonReaders.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ArrayReader.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ClassScope.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/EnumReader.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ExistingSubtypeAspect.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/GlobalScope.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/InterfaceReader.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/LazyCachedMethodHandler.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/MapReader.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ObjectValueReader.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/PrimitiveValueReader.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/RawValueReader.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderGenerator.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/StringIntPairValueReader.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/SubtypeCaster.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TextOutput.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeHandler.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeRef.java
platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ValueReader.java

index a9df79ecf0d1861d31042847d91a0968140330ec..d2831df2b473e2a387cd046791c4df04e9abe261 100644 (file)
@@ -146,6 +146,7 @@ public class AsyncPromise<T> extends Promise<T> implements Getter<T> {
     return promise;
   }
 
+  @Override
   void notify(@NotNull final AsyncPromise<T> child) {
     switch (state) {
       case PENDING:
index 3653bd6f634f1dcda10452ff9b4fdefbc702f61b..fcf1749a5b69b935426e7a6cc8e458bdf7fc30a8 100644 (file)
@@ -66,4 +66,9 @@ class DonePromise<T> extends Promise<T> implements Getter<T> {
   public T get() {
     return result;
   }
+
+  @Override
+  void notify(@NotNull AsyncPromise<T> child) {
+    child.setResult(result);
+  }
 }
\ No newline at end of file
index c68d45780c0608e6eb282ca092b2731222ccd850..221ee48fe4a625e1dfb7636d08471ee2ae47024d 100644 (file)
@@ -184,4 +184,6 @@ public abstract class Promise<T> {
       return this;
     }
   }
+
+  abstract void notify(@NotNull AsyncPromise<T> child);
 }
\ No newline at end of file
index f6821f9e074ef2918e78d2f6b8a3c5f43c3a3c13..06d630d0e074e916481942d3e8b108459b8e3fb9 100644 (file)
@@ -97,7 +97,8 @@ public abstract class PromiseManager<HOST, VALUE> {
     }
 
     Promise<VALUE> effectivePromise = load(host);
-    ((AsyncPromise<VALUE>)effectivePromise).notify((AsyncPromise<VALUE>)promise);
+    fieldUpdater.compareAndSet(host, promise, effectivePromise);
+    effectivePromise.notify((AsyncPromise<VALUE>)promise);
     return effectivePromise;
   }
 }
\ No newline at end of file
index 452a6bfae2b1845ab1dad941de6688c5424450dd..d08ae2025218168f0bd967ec5ef34a68870f04e8 100644 (file)
@@ -55,4 +55,9 @@ class RejectedPromise<T> extends Promise<T> {
   public State getState() {
     return State.REJECTED;
   }
+
+  @Override
+  void notify(@NotNull AsyncPromise<T> child) {
+    child.setError(error);
+  }
 }
\ No newline at end of file
index fa7f76383f867f9a28c74b449a386e374fb21f82..6316d746464ba55396dbdc6a88953a52ec1d96cf 100644 (file)
@@ -4,76 +4,35 @@ import com.intellij.util.Consumer;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.concurrency.Promise;
-import org.jetbrains.concurrency.PromiseManager;
 import org.jetbrains.debugger.values.ObjectValue;
 import org.jetbrains.debugger.values.ValueManager;
 
 import java.util.List;
 
-public abstract class DeclarativeScope<VALUE_LOADER extends ValueManager> extends ScopeBase {
-  private static final PromiseManager<DeclarativeScope, List<Variable>> VARIABLES_LOADER =
-    new PromiseManager<DeclarativeScope, List<Variable>>(DeclarativeScope.class) {
-      @Override
-      public boolean isUpToDate(@NotNull DeclarativeScope host, @NotNull List<Variable> data) {
-        return host.valueManager.getCacheStamp() == host.cacheStamp;
-      }
-
-      @NotNull
-      @Override
-      public Promise<List<Variable>> load(@NotNull DeclarativeScope host) {
-        //noinspection unchecked
-        return host.loadVariables();
-      }
-    };
+public abstract class DeclarativeScope<VALUE_MANAGER extends ValueManager> extends ScopeBase {
+  protected VariablesHost<VALUE_MANAGER> childrenManager;
 
-  @SuppressWarnings("UnusedDeclaration")
-  private volatile Promise<List<Variable>> variables;
-
-  private volatile int cacheStamp = -1;
-
-  protected final VALUE_LOADER valueManager;
-
-  protected DeclarativeScope(@NotNull Type type, @Nullable String description, @NotNull VALUE_LOADER valueManager) {
+  protected DeclarativeScope(@NotNull Type type, @Nullable String description) {
     super(type, description);
-
-    this.valueManager = valueManager;
-  }
-
-  /**
-   * You must call {@link #updateCacheStamp()} when data loaded
-   */
-  @NotNull
-  protected abstract Promise<List<Variable>> loadVariables();
-
-  protected final void updateCacheStamp() {
-    cacheStamp = valueManager.getCacheStamp();
   }
 
   @NotNull
   protected final Promise<List<Variable>> loadScopeObjectProperties(@NotNull ObjectValue value) {
-    if (valueManager.isObsolete()) {
+    if (childrenManager.valueManager.isObsolete()) {
       return ValueManager.reject();
     }
 
     return value.getProperties().done(new Consumer<List<Variable>>() {
       @Override
       public void consume(List<Variable> variables) {
-        updateCacheStamp();
+        childrenManager.updateCacheStamp();
       }
     });
   }
 
   @NotNull
   @Override
-  public final Promise<List<Variable>> getVariables() {
-    return VARIABLES_LOADER.get(this);
-  }
-
-  @NotNull
-  @Override
-  public Promise<Void> clearCaches() {
-    cacheStamp = -1;
-    VARIABLES_LOADER.reset(this);
-    return Promise.DONE;
+  public final VariablesHost getVariablesHost() {
+    return childrenManager;
   }
 }
\ No newline at end of file
diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/ObjectScope.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/ObjectScope.java
new file mode 100644 (file)
index 0000000..b10d887
--- /dev/null
@@ -0,0 +1,20 @@
+package org.jetbrains.debugger;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.debugger.values.ObjectValue;
+
+public final class ObjectScope extends ScopeBase implements Scope {
+  private final ObjectValue value;
+
+  public ObjectScope(@NotNull Type type, @NotNull ObjectValue value) {
+    super(type, value.getValueString());
+
+    this.value = value;
+  }
+
+  @NotNull
+  @Override
+  public VariablesHost getVariablesHost() {
+    return value.getVariablesHost();
+  }
+}
\ No newline at end of file
index f1af10ae3efd317b1a980e7cf75f7e7e9df0d0a0..e92f1c23d47bc802129c34d29b5810e4075a5150 100644 (file)
@@ -2,9 +2,6 @@ package org.jetbrains.debugger;
 
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
-import org.jetbrains.concurrency.Promise;
-
-import java.util.List;
 
 public interface Scope {
   enum Type {
@@ -29,14 +26,7 @@ public interface Scope {
   String getDescription();
 
   @NotNull
-  Promise<List<Variable>> getVariables();
+  VariablesHost<?> getVariablesHost();
 
   boolean isGlobal();
-
-  /**
-   * Some backends requires to reload the whole call stack on scope variable modification, but not all API is asynchronous (compromise, to not increase complexity),
-   * for example, {@link CallFrame#getVariableScopes()} is not asynchronous method. So, you must use returned callback to postpone your code working with updated data.
-   */
-  @NotNull
-  Promise<Void> clearCaches();
 }
\ No newline at end of file
index d1bfe3758797924c3b13179ecbd2a04dac6f47f9..8abd7494ea66d7b60b70dcf3442229c8a528b994 100644 (file)
@@ -14,13 +14,13 @@ public abstract class ScopeBase implements Scope {
 
   @Nullable
   @Override
-  public String getDescription() {
+  public final String getDescription() {
     return description;
   }
 
   @NotNull
   @Override
-  public Type getType() {
+  public final Type getType() {
     return type;
   }
 
diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/VariablesHost.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/VariablesHost.java
new file mode 100644 (file)
index 0000000..95194a9
--- /dev/null
@@ -0,0 +1,65 @@
+package org.jetbrains.debugger;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.concurrency.Promise;
+import org.jetbrains.concurrency.PromiseManager;
+import org.jetbrains.debugger.values.ValueManager;
+
+import java.util.List;
+
+public abstract class VariablesHost<VALUE_MANAGER extends ValueManager> {
+  @SuppressWarnings("unchecked")
+  public static final PromiseManager<VariablesHost, List<Variable>> VARIABLES_LOADER =
+    new PromiseManager<VariablesHost, List<Variable>>(VariablesHost.class) {
+      @Override
+      public boolean isUpToDate(@NotNull VariablesHost host, @NotNull List<Variable> data) {
+        return host.valueManager.getCacheStamp() == host.cacheStamp;
+      }
+
+      @Override
+      public Promise<List<Variable>> load(@NotNull VariablesHost host) {
+        if (host.valueManager.isObsolete()) {
+          return ValueManager.reject();
+        }
+        else {
+          return host.load();
+        }
+      }
+    };
+
+  @SuppressWarnings("UnusedDeclaration")
+  private volatile Promise<List<Variable>> result;
+
+  private volatile int cacheStamp = -1;
+
+  public final VALUE_MANAGER valueManager;
+
+  public VariablesHost(@NotNull VALUE_MANAGER manager) {
+    valueManager = manager;
+  }
+
+  /**
+   * You must call {@link #updateCacheStamp()} when data loaded
+   */
+  @NotNull
+  public final Promise<List<Variable>> get() {
+    return VARIABLES_LOADER.get(this);
+  }
+
+  @NotNull
+  protected abstract Promise<List<Variable>> load();
+
+  public final void updateCacheStamp() {
+    cacheStamp = valueManager.getCacheStamp();
+  }
+
+  /**
+   * Some backends requires to reload the whole call stack on scope variable modification, but not all API is asynchronous (compromise, to not increase complexity),
+   * for example, {@link CallFrame#getVariableScopes()} is not asynchronous method. So, you must use returned callback to postpone your code working with updated data.
+   */
+  public Promise<Void> clearCaches() {
+    cacheStamp = -1;
+    VARIABLES_LOADER.reset(this);
+    return Promise.DONE;
+  }
+}
index 03dea7cd438637556244fc8a47eb5ee8313d5822..e7261ce293e4d1225004ea1317ed4e8ff35bfcea 100755 (executable)
@@ -5,6 +5,7 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.concurrency.Promise;
 import org.jetbrains.debugger.Variable;
+import org.jetbrains.debugger.VariablesHost;
 
 import java.util.List;
 
@@ -12,14 +13,15 @@ import java.util.List;
  * A compound value that has zero or more properties
  */
 public interface ObjectValue extends Value {
-  void clearCaches();
-
   @Nullable
   String getClassName();
 
   @NotNull
   Promise<List<Variable>> getProperties();
 
+  @NotNull
+  VariablesHost getVariablesHost();
+
   /**
    * from (inclusive) to (exclusive) ranges of array elements or elements if less than bucketThreshold
    *
@@ -39,6 +41,4 @@ public interface ObjectValue extends Value {
    */
   @NotNull
   ThreeState hasIndexedProperties();
-
-  int getCacheStamp();
 }
\ No newline at end of file
index 635266cf9bb824753c197cb92fa05ada781a909c..00de61f0d319658e190a1431bb56ba0fa9a542f3 100644 (file)
@@ -3,57 +3,23 @@ package org.jetbrains.debugger.values;
 import com.intellij.util.ThreeState;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
-import org.jetbrains.concurrency.AsyncPromise;
 import org.jetbrains.concurrency.Promise;
-import org.jetbrains.concurrency.PromiseManager;
 import org.jetbrains.debugger.Variable;
+import org.jetbrains.debugger.VariablesHost;
 
 import java.util.List;
 
 public abstract class ObjectValueBase<VALUE_LOADER extends ValueManager> extends ValueBase implements ObjectValue {
-  @SuppressWarnings("unchecked")
-  private static final PromiseManager<ObjectValueBase, List<Variable>> PROPERTIES_LOADER =
-    new PromiseManager<ObjectValueBase, List<Variable>>(ObjectValueBase.class) {
-      @Override
-      public boolean isUpToDate(@NotNull ObjectValueBase host, @NotNull List<Variable> data) {
-        return host.valueManager.getCacheStamp() == host.cacheStamp;
-      }
+  protected VariablesHost<VALUE_LOADER> childrenManager;
 
-      @Override
-      public Promise<List<Variable>> load(@NotNull ObjectValueBase host) {
-        if (host.valueManager.isObsolete()) {
-          return ValueManager.reject();
-        }
-        else {
-          return ((AsyncPromise<List<Variable>>)host.loadProperties());
-        }
-      }
-    };
-
-  @SuppressWarnings("UnusedDeclaration")
-  private volatile Promise<List<? extends Variable>> properties;
-
-  private volatile int cacheStamp = -1;
-
-  protected final VALUE_LOADER valueManager;
-
-  public ObjectValueBase(@NotNull ValueType type, @NotNull VALUE_LOADER valueManager) {
+  public ObjectValueBase(@NotNull ValueType type) {
     super(type);
-
-    this.valueManager = valueManager;
-  }
-
-  @NotNull
-  protected abstract Promise<List<Variable>> loadProperties();
-
-  protected final void updateCacheStamp() {
-    cacheStamp = valueManager.getCacheStamp();
   }
 
   @NotNull
   @Override
   public final Promise<List<Variable>> getProperties() {
-    return PROPERTIES_LOADER.get(this);
+    return childrenManager.get();
   }
 
   @Nullable
@@ -80,14 +46,9 @@ public abstract class ObjectValueBase<VALUE_LOADER extends ValueManager> extends
     return Promise.REJECTED;
   }
 
+  @NotNull
   @Override
-  public int getCacheStamp() {
-    return cacheStamp;
-  }
-
-  @Override
-  public void clearCaches() {
-    cacheStamp = -1;
-    PROPERTIES_LOADER.reset(this);
+  public VariablesHost getVariablesHost() {
+    return childrenManager;
   }
 }
\ No newline at end of file
index f03565f2defaecd9ccb63104a9583dd8ae76c5ba..dca53d363cf32cf30aed09045df094270ad0bc87 100644 (file)
@@ -7,6 +7,9 @@ public class PrimitiveValue extends ValueBase {
   public static final PrimitiveValue NULL_VALUE = new PrimitiveValue(ValueType.NULL, "null");
   public static final PrimitiveValue UNDEFINED_VALUE = new PrimitiveValue(ValueType.UNDEFINED, "undefined");
 
+  private static final PrimitiveValue TRUE = new PrimitiveValue(ValueType.BOOLEAN, "true");
+  private static final PrimitiveValue FALSE = new PrimitiveValue(ValueType.BOOLEAN, "false");
+
   private final String valueString;
 
   public PrimitiveValue(@NotNull ValueType type, @NotNull String valueString) {
@@ -15,6 +18,11 @@ public class PrimitiveValue extends ValueBase {
     this.valueString = valueString;
   }
 
+  @NotNull
+  public static PrimitiveValue bool(@NotNull String value) {
+    return value.equals("true") ? TRUE : FALSE;
+  }
+
   public PrimitiveValue(ValueType type, int value) {
     this(type, Integer.toString(value));
   }
index 7d573bcb632e469445f977b4b01b916440ef117c..2110010eb83b818cb545b16c2ab2ef221e950c42 100644 (file)
@@ -29,57 +29,58 @@ public final class Variables {
                                                     @NotNull final XCompositeNode node,
                                                     @NotNull final VariableContext context,
                                                     final boolean isLast) {
-    return scope.getVariables().then(new AsyncFunction<List<Variable>, Void>() {
-      @NotNull
-      @Override
-      public Promise<Void> fun(List<Variable> variables) {
-        if (node.isObsolete()) {
-          return Promise.REJECTED;
-        }
+    return scope.getVariablesHost().get()
+      .then(new AsyncFunction<List<Variable>, Void>() {
+        @NotNull
+        @Override
+        public Promise<Void> fun(List<Variable> variables) {
+          if (node.isObsolete()) {
+            return Promise.REJECTED;
+          }
 
-        final MemberFilter memberFilter = context.createMemberFilter();
-        Collection<Variable> additionalVariables = memberFilter.getAdditionalVariables();
-        List<Variable> properties = new ArrayList<Variable>(variables.size() + additionalVariables.size());
-        List<Variable> functions = new SmartList<Variable>();
-        for (Variable variable : variables) {
-          if (memberFilter.isMemberVisible(variable, false)) {
-            Value value = variable.getValue();
-            if (value != null &&
-                value.getType() == ValueType.FUNCTION &&
-                value.getValueString() != null &&
-                !UNNAMED_FUNCTION_PATTERN.matcher(value.getValueString()).lookingAt()) {
-              functions.add(variable);
-            }
-            else {
-              properties.add(variable);
+          final MemberFilter memberFilter = context.createMemberFilter();
+          Collection<Variable> additionalVariables = memberFilter.getAdditionalVariables();
+          List<Variable> properties = new ArrayList<Variable>(variables.size() + additionalVariables.size());
+          List<Variable> functions = new SmartList<Variable>();
+          for (Variable variable : variables) {
+            if (memberFilter.isMemberVisible(variable, false)) {
+              Value value = variable.getValue();
+              if (value != null &&
+                  value.getType() == ValueType.FUNCTION &&
+                  value.getValueString() != null &&
+                  !UNNAMED_FUNCTION_PATTERN.matcher(value.getValueString()).lookingAt()) {
+                functions.add(variable);
+              }
+              else {
+                properties.add(variable);
+              }
             }
           }
-        }
 
-        Collections.sort(properties, memberFilter.hasNameMappings() ? new Comparator<Variable>() {
-          @Override
-          public int compare(@NotNull Variable o1, @NotNull Variable o2) {
-            return naturalCompare(memberFilter.getName(o1), memberFilter.getName(o2));
-          }
-        } : NATURAL_NAME_COMPARATOR);
-        sort(functions);
+          Collections.sort(properties, memberFilter.hasNameMappings() ? new Comparator<Variable>() {
+            @Override
+            public int compare(@NotNull Variable o1, @NotNull Variable o2) {
+              return naturalCompare(memberFilter.getName(o1), memberFilter.getName(o2));
+            }
+          } : NATURAL_NAME_COMPARATOR);
+          sort(functions);
 
-        addAditionalVariables(variables, additionalVariables, properties, memberFilter);
+          addAditionalVariables(variables, additionalVariables, properties, memberFilter);
 
-        if (!properties.isEmpty()) {
-          node.addChildren(createVariablesList(properties, context, memberFilter), functions.isEmpty() && isLast);
-        }
+          if (!properties.isEmpty()) {
+            node.addChildren(createVariablesList(properties, context, memberFilter), functions.isEmpty() && isLast);
+          }
 
-        if (!functions.isEmpty()) {
-          node.addChildren(XValueChildrenList.bottomGroup(new VariablesGroup("Functions", functions, context)), isLast);
-        }
-        else if (isLast && properties.isEmpty()) {
-          node.addChildren(XValueChildrenList.EMPTY, true);
-        }
+          if (!functions.isEmpty()) {
+            node.addChildren(XValueChildrenList.bottomGroup(new VariablesGroup("Functions", functions, context)), isLast);
+          }
+          else if (isLast && properties.isEmpty()) {
+            node.addChildren(XValueChildrenList.EMPTY, true);
+          }
 
-        return Promise.DONE;
-      }
-    });
+          return Promise.DONE;
+        }
+      });
   }
 
   @Nullable
index 3b960b8636a9815ef0d1baea2f310b9a0672c965..0745f4310e5c6e73e0e9cdff3520abdcb0e3488c 100644 (file)
@@ -29,4 +29,6 @@ public @interface JsonField {
   boolean allowAnyPrimitiveValueAndMap() default false;
 
   boolean optional() default false;
+
+  String primitiveValue() default "";
 }
\ No newline at end of file
index 757536c9d018ced08ee8d7976cec5be328104d76..ea324fbb6d37bb80d841adcc9639dc90c7c0a999 100644 (file)
@@ -7,6 +7,7 @@ import gnu.trove.THashMap;
 import gnu.trove.TIntArrayList;
 import gnu.trove.TLongArrayList;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.jetbrains.io.JsonReaderEx;
 
 import java.util.ArrayList;
@@ -30,23 +31,13 @@ public final class JsonReaders {
 
   public static Object readRawStringOrMap(JsonReaderEx reader) {
     if (reader.peek() == JsonToken.BEGIN_OBJECT) {
-      return readMap(reader);
+      return readMap(reader, null);
     }
     else {
       return reader.nextString(true);
     }
   }
 
-  public static <T extends Enum<T>> T readEnum(JsonReaderEx reader, String fieldName, Class<T> enumClass) {
-    checkIsNull(reader, fieldName);
-    try {
-      return Enum.valueOf(enumClass, readEnumName(reader));
-    }
-    catch (IllegalArgumentException ignored) {
-      return Enum.valueOf(enumClass, "NO_ENUM_CONST");
-    }
-  }
-
   public static String convertRawEnumName(@NotNull String enumValue) {
     StringBuilder builder = new StringBuilder(enumValue.length() + 4);
     boolean prevIsLowerCase = false;
@@ -72,19 +63,21 @@ public final class JsonReaders {
     return builder.toString();
   }
 
-  private static String readEnumName(JsonReaderEx reader) {
-    return convertRawEnumName(reader.nextString());
-  }
-
-  public static <T extends Enum<T>> T readEnum(JsonReaderEx reader, Class<T> enumClass) {
+  public static <T extends Enum<T>> T readEnum(@NotNull JsonReaderEx reader, @NotNull Class<T> enumClass) {
     if (reader.peek() == JsonToken.NULL) {
       reader.skipValue();
       return null;
     }
-    return Enum.valueOf(enumClass, readEnumName(reader));
+
+    try {
+      return Enum.valueOf(enumClass, convertRawEnumName(reader.nextString()));
+    }
+    catch (IllegalArgumentException ignored) {
+      return Enum.valueOf(enumClass, "NO_ENUM_CONST");
+    }
   }
 
-  public static <T> List<T> readObjectArray(JsonReaderEx reader, ObjectFactory<T> factory) {
+  public static <T> List<T> readObjectArray(@NotNull JsonReaderEx reader, @NotNull ObjectFactory<T> factory) {
     if (reader.peek() == JsonToken.NULL) {
       reader.skipValue();
       return null;
@@ -105,13 +98,30 @@ public final class JsonReaders {
     return result;
   }
 
-  public static Map<?, ?> readMap(JsonReaderEx reader) {
+  public static <T> Map<String, T> readMap(@NotNull JsonReaderEx reader, @Nullable ObjectFactory<T> factory) {
+    if (reader.peek() == JsonToken.NULL) {
+      reader.skipValue();
+      return null;
+    }
+
     reader.beginObject();
     if (!reader.hasNext()) {
       reader.endObject();
       return Collections.emptyMap();
     }
-    return nextObject(reader);
+
+    Map<String, T> map = new THashMap<String, T>();
+    while (reader.hasNext()) {
+      if (factory == null) {
+        //noinspection unchecked
+        map.put(reader.nextName(), (T)read(reader));
+      }
+      else {
+        map.put(reader.nextName(), factory.read(reader));
+      }
+    }
+    reader.endObject();
+    return map;
   }
 
   public static Object read(JsonReaderEx reader) {
index ea679c00aefa0e4c948cb7629dd0af1a49edeae3..08b397b9239bca006ffaa871c83284cdd4d569aa 100644 (file)
@@ -1,10 +1,12 @@
 package org.jetbrains.protocolReader;
 
+import org.jetbrains.annotations.NotNull;
+
 class ArrayReader extends ValueReader {
   private final ValueReader componentParser;
   private final boolean isList;
 
-  ArrayReader(ValueReader componentParser, boolean isList) {
+  ArrayReader(@NotNull ValueReader componentParser, boolean isList) {
     super();
 
     this.componentParser = componentParser;
@@ -12,7 +14,7 @@ class ArrayReader extends ValueReader {
   }
 
   @Override
-  public void appendFinishedValueTypeName(TextOutput out) {
+  public void appendFinishedValueTypeName(@NotNull TextOutput out) {
     if (isList) {
       out.append("java.util.List<");
       componentParser.appendFinishedValueTypeName(out);
@@ -25,16 +27,7 @@ class ArrayReader extends ValueReader {
   }
 
   @Override
-  public void appendInternalValueTypeName(FileScope scope, TextOutput out) {
-    appendFinishedValueTypeName(out);
-  }
-
-  @Override
-  void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, TextOutput out) {
+  void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, @NotNull TextOutput out) {
     componentParser.writeArrayReadCode(scope, subtyping, out);
   }
-
-  @Override
-  void writeArrayReadCode(ClassScope scope, boolean subtyping, TextOutput out) {
-  }
 }
index 6b6e108abc9e58ca314056acb98a8ae891bbc834..7f0a6701846ce866784e69987940026356f816ef 100644 (file)
@@ -9,12 +9,7 @@ public class ClassScope extends FileScope {
   }
 
   public ClassScope getRootClassScope() {
-    if (parentClass == null) {
-      return this;
-    }
-    else {
-      return parentClass.getRootClassScope();
-    }
+    return parentClass == null ? this : parentClass.getRootClassScope();
   }
 
   @Override
index 271831ae5c6812275feccb5833afe9d88599d736..a0d794d0cb0fc00ed7d820da310b8f6b8edf6f79 100644 (file)
@@ -1,9 +1,7 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
 package org.jetbrains.protocolReader;
 
+import org.jetbrains.annotations.NotNull;
+
 class EnumReader<T extends Enum<T>> extends ValueReader {
   public static <T extends Enum<T>> EnumReader<T> create(Class<T> enumTypeClass) {
     return new EnumReader<>(enumTypeClass);
@@ -17,20 +15,13 @@ class EnumReader<T extends Enum<T>> extends ValueReader {
   }
 
   @Override
-  public void appendFinishedValueTypeName(TextOutput out) {
+  public void appendFinishedValueTypeName(@NotNull TextOutput out) {
     out.append(enumClass.getCanonicalName());
   }
 
   @Override
-  void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, TextOutput out) {
+  void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, @NotNull TextOutput out) {
     beginReadCall("Enum", subtyping, out);
     out.comma().append(enumClass.getCanonicalName()).append(".class").append(')');
   }
-
-  @Override
-  void writeArrayReadCode(ClassScope scope,
-                          boolean subtyping,
-                          TextOutput out) {
-    throw new UnsupportedOperationException();
-  }
 }
index 6d4bbfe2b828123d61d36cbdabc0258829408a47..7a0f739d0b0b482377ecf12bf15fd3f3b4f3884d 100644 (file)
@@ -15,16 +15,16 @@ class ExistingSubtypeAspect {
   }
 
   void writeGetSuperMethodJava(@NotNull TextOutput out) {
-    out.newLine().append("@Override").newLine().append("public ").append(jsonSuperClass.get().getTypeClass().getCanonicalName() ).append(" getSuper()").openBlock();
+    out.newLine().append("@Override").newLine().append("public ").append(jsonSuperClass.type.typeClass.getCanonicalName() ).append(" getSuper()").openBlock();
     out.append("return ").append(Util.BASE_VALUE_PREFIX).semi().closeBlock();
   }
 
   void writeSuperFieldJava(@NotNull TextOutput out) {
-    out.newLine().append("private final ").append(jsonSuperClass.get().getTypeClass().getCanonicalName()).append(' ').append(Util.BASE_VALUE_PREFIX).semi().newLine();
+    out.newLine().append("private final ").append(jsonSuperClass.type.typeClass.getCanonicalName()).append(' ').append(Util.BASE_VALUE_PREFIX).semi().newLine();
   }
 
   void writeSuperConstructorParamJava(@NotNull TextOutput out) {
-    out.comma().append(jsonSuperClass.get().getTypeClass().getCanonicalName()).append(' ').append(Util.BASE_VALUE_PREFIX);
+    out.comma().append(jsonSuperClass.type.typeClass.getCanonicalName()).append(' ').append(Util.BASE_VALUE_PREFIX);
   }
 
   void writeSuperConstructorInitialization(@NotNull TextOutput out) {
@@ -34,7 +34,7 @@ class ExistingSubtypeAspect {
   void writeParseMethod(@NotNull String className, @NotNull ClassScope scope, @NotNull TextOutput out) {
     out.newLine().append("public static ").append(className).space().append("parse").append('(').append(Util.JSON_READER_PARAMETER_DEF).append(", String name").append(')').openBlock();
     out.append("return ");
-    jsonSuperClass.get().writeInstantiateCode(scope, out);
+    jsonSuperClass.type.writeInstantiateCode(scope, out);
     out.append('(').append(Util.READER_NAME).append(", name)").append('.');
     subtypeCaster.writeJava(out);
     out.semi().closeBlock();
index bd4f2b62852baaf961e1bb4a41dfa5210065b3ee..7d4738f824e00ca1c218bf4ade066a05c6a320ed 100644 (file)
@@ -55,7 +55,7 @@ final class FieldProcessor<T> {
         }
         methodHandlerMap.put(method, methodHandler);
       }
-      catch (JsonProtocolModelParseException e) {
+      catch (Exception e) {
         throw new JsonProtocolModelParseException("Problem with method " + method, e);
       }
     }
@@ -79,7 +79,13 @@ final class FieldProcessor<T> {
       }
     }
 
-    ValueReader fieldTypeParser = reader.getFieldTypeParser(genericReturnType, false, method);
+    ValueReader fieldTypeParser;
+    try {
+      fieldTypeParser = reader.getFieldTypeParser(genericReturnType, false, method);
+    }
+    catch (Exception e) {
+      throw new RuntimeException("Cannot create field type parser for method " + method, e);
+    }
     if (fieldTypeParser != InterfaceReader.VOID_PARSER) {
       fieldLoaders.add(new FieldLoader(fieldName, fieldTypeParser));
     }
@@ -130,6 +136,7 @@ final class FieldProcessor<T> {
     return methodHandlerMap;
   }
 
+  @NotNull
   private VolatileFieldBinding allocateVolatileField(final ValueReader fieldTypeParser, boolean internalType) {
     int position = volatileFields.size();
     FieldTypeInfo fieldTypeInfo;
index 28c91b7520d3d3b9a57788b67a4f5ef7815c9799..c3c7dacd5a1f9e46d8f341a5c51fd65baae4e576 100644 (file)
@@ -67,7 +67,7 @@ public class GlobalScope {
       }
 
       for (Map<Class<?>, String> base : basePackages) {
-        String result = base.get(typeHandler.getTypeClass());
+        String result = base.get(typeHandler.typeClass);
         if (result != null) {
           return result;
         }
index 446a0a9150e172320318704ffe17bfdb2048eef2..b236e6d3de51e60546fe5ce33550fc6f194492b8 100644 (file)
@@ -1,6 +1,7 @@
 package org.jetbrains.protocolReader;
 
 import gnu.trove.THashSet;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.io.JsonReaderEx;
 import org.jetbrains.jsonProtocol.JsonField;
@@ -29,7 +30,7 @@ class InterfaceReader {
   private static final PrimitiveValueReader RAW_STRING_PARSER = new PrimitiveValueReader("String", null, true);
   private static final PrimitiveValueReader RAW_STRING_OR_MAP_PARSER = new PrimitiveValueReader("Object", null, true) {
     @Override
-    void writeReadCode(ClassScope methodScope, boolean subtyping, String fieldName, TextOutput out) {
+    void writeReadCode(ClassScope methodScope, boolean subtyping, String fieldName, @NotNull TextOutput out) {
       out.append("readRawStringOrMap(");
       addReaderParameter(subtyping, out);
       out.append(')');
@@ -38,25 +39,20 @@ class InterfaceReader {
 
   private static final RawValueReader JSON_PARSER = new RawValueReader(false);
 
-  private static final MapReader MAP_PARSER = new MapReader(false);
+  private static final MapReader MAP_PARSER = new MapReader(null);
 
   private static final StringIntPairValueReader STRING_INT_PAIR_PARSER = new StringIntPairValueReader();
 
   final static ValueReader VOID_PARSER = new ValueReader() {
     @Override
-    public void appendFinishedValueTypeName(TextOutput out) {
+    public void appendFinishedValueTypeName(@NotNull TextOutput out) {
       out.append("void");
     }
 
     @Override
-    void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, TextOutput out) {
+    void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, @NotNull TextOutput out) {
       out.append("null");
     }
-
-    @Override
-    void writeArrayReadCode(ClassScope scope, boolean subtyping, TextOutput out) {
-      throw new UnsupportedOperationException();
-    }
   };
 
   private final LinkedHashMap<Class<?>, TypeHandler<?>> typeToTypeHandler;
@@ -97,22 +93,21 @@ class InterfaceReader {
       // refs can be modified - new items can be added
       //noinspection ForLoopReplaceableByForEach
       for (int i = 0, n = refs.size(); i < n; i++) {
-        TypeRef<?> ref = refs.get(i);
-        TypeHandler<?> type = typeToTypeHandler.get(ref.typeClass);
-        if (type == null) {
+        TypeRef ref = refs.get(i);
+        ref.type = typeToTypeHandler.get(ref.typeClass);
+        if (ref.type == null) {
           createIfNotExists(ref.typeClass);
           hasUnresolved = true;
-          type = typeToTypeHandler.get(ref.typeClass);
-          if (type == null) {
+          ref.type = typeToTypeHandler.get(ref.typeClass);
+          if (ref.type == null) {
             throw new IllegalStateException();
           }
         }
-        ref.set(type);
       }
     }
 
     for (SubtypeCaster subtypeCaster : subtypeCasters) {
-      ExistingSubtypeAspect subtypeSupport = subtypeCaster.getSubtypeHandler().getSubtypeSupport();
+      ExistingSubtypeAspect subtypeSupport = subtypeCaster.getSubtypeHandler().subtypeAspect;
       if (subtypeSupport != null) {
         subtypeSupport.setSubtypeCaster(subtypeCaster);
       }
@@ -140,10 +135,10 @@ class InterfaceReader {
     }
 
     TypeHandler<?> typeHandler = createTypeHandler(typeClass);
-    for (TypeRef<?> ref : refs) {
+    for (TypeRef ref : refs) {
       if (ref.typeClass == typeClass) {
-        assert ref.get() == null;
-        ref.set(typeHandler);
+        assert ref.type == null;
+        ref.type = typeHandler;
         break;
       }
     }
@@ -213,8 +208,7 @@ class InterfaceReader {
         return STRING_INT_PAIR_PARSER;
       }
       else if (typeClass.isArray()) {
-        return new ArrayReader(getFieldTypeParser(typeClass.getComponentType(), false, null), false
-        );
+        return new ArrayReader(getFieldTypeParser(typeClass.getComponentType(), false, null), false);
       }
       else if (typeClass.isEnum()) {
         //noinspection unchecked
@@ -222,38 +216,34 @@ class InterfaceReader {
       }
       TypeRef<?> ref = getTypeRef(typeClass);
       if (ref != null) {
-        return createJsonParser(ref, isSubtyping);
+        JsonField jsonField = method == null ? null : method.getAnnotation(JsonField.class);
+        return new ObjectValueReader<>(ref, isSubtyping, jsonField == null ? null : jsonField.primitiveValue());
       }
-      throw new JsonProtocolModelParseException("Method return type " + type + " (simple class) not supported");
+      throw new UnsupportedOperationException("Method return type " + type + " (simple class) not supported");
     }
     else if (type instanceof ParameterizedType) {
       ParameterizedType parameterizedType = (ParameterizedType)type;
-      if (parameterizedType.getRawType() == List.class) {
-        Type argumentType = parameterizedType.getActualTypeArguments()[0];
+      boolean isList = parameterizedType.getRawType() == List.class;
+      if (isList || parameterizedType.getRawType() == Map.class) {
+        Type argumentType = parameterizedType.getActualTypeArguments()[isList ? 0 : 1];
         if (argumentType instanceof WildcardType) {
           WildcardType wildcard = (WildcardType)argumentType;
           if (wildcard.getLowerBounds().length == 0 && wildcard.getUpperBounds().length == 1) {
             argumentType = wildcard.getUpperBounds()[0];
           }
         }
-        return new ArrayReader(getFieldTypeParser(argumentType, false, method), true);
-      }
-      else if (parameterizedType.getRawType() == Map.class) {
-        return MAP_PARSER;
+        ValueReader componentParser = getFieldTypeParser(argumentType, false, method);
+        return isList ? new ArrayReader(componentParser, true) : new MapReader(componentParser);
       }
       else {
-        throw new JsonProtocolModelParseException("Method return type " + type + " (generic) not supported");
+        throw new UnsupportedOperationException("Method return type " + type + " (generic) not supported");
       }
     }
     else {
-      throw new JsonProtocolModelParseException("Method return type " + type + " not supported");
+      throw new UnsupportedOperationException("Method return type " + type + " not supported");
     }
   }
 
-  private static <T> ObjectValueReader<T> createJsonParser(TypeRef<T> type, boolean isSubtyping) {
-    return new ObjectValueReader<>(type, isSubtyping);
-  }
-
   <T> TypeRef<T> getTypeRef(Class<T> typeClass) {
     TypeRef<T> result = new TypeRef<>(typeClass);
     refs.add(result);
@@ -276,8 +266,7 @@ class InterfaceReader {
       }
       Class<?> paramClass = (Class<?>)param;
       if (result != null) {
-        throw new JsonProtocolModelParseException("Already has superclass " +
-                                                  result.getTypeClass().getName());
+        throw new JsonProtocolModelParseException("Already has superclass " + result.typeClass.getName());
       }
       result = getTypeRef(paramClass);
       if (result == null) {
index c1e962f98598e8d12c3fafbe17c5ce91e41808f3..68f80dc1042fbf46f391a4cecb582419d67cd455 100644 (file)
@@ -21,7 +21,7 @@ class LazyCachedMethodHandler extends MethodHandler {
       Util.writeJavaTypeName(m.getGenericReturnType(), out);
     }
     else {
-      out.append(scope.getTypeImplReference(objectValueParser.getType().get()));
+      out.append(scope.getTypeImplReference(objectValueParser.getType().type));
     }
   }
 
index c7b9c6578a92f6423adcfa166154080f1f1fdd00..f1e7ce339e1fcd943d64447742d3d983f6cd52e2 100644 (file)
@@ -1,25 +1,43 @@
 package org.jetbrains.protocolReader;
 
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
 public class MapReader extends ValueReader {
-  MapReader(boolean nullable) {
+  private final ValueReader componentParser;
+
+  MapReader(@Nullable ValueReader componentParser) {
     super();
+
+    if (componentParser == null || componentParser instanceof ObjectValueReader) {
+      this.componentParser = componentParser;
+    }
+    else {
+      // if primitive (String), we don't need to use factory to read value
+      this.componentParser = null;
+    }
   }
 
   @Override
-  public void appendFinishedValueTypeName(TextOutput out) {
+  public void appendFinishedValueTypeName(@NotNull TextOutput out) {
     out.append("java.util.Map");
+    if (componentParser != null) {
+      out.append('<');
+      out.append("String, ");
+      componentParser.appendFinishedValueTypeName(out);
+      out.append('>');
+    }
   }
 
   @Override
-  void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, TextOutput out) {
+  void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, @NotNull TextOutput out) {
     beginReadCall("Map", subtyping, out);
+    if (componentParser == null) {
+      out.comma().append("null");
+    }
+    else {
+      ((ObjectValueReader)componentParser).writeFactoryArgument(scope, out);
+    }
     out.append(')');
   }
-
-  @Override
-  void writeArrayReadCode(ClassScope scope,
-                          boolean subtyping,
-                          TextOutput out) {
-    throw new UnsupportedOperationException();
-  }
 }
index 686fc5aa43dbcb2534ea90294c64c27738e5d566..1b4b03fdca85ef2ca60607c9c84017d1ad1d59aa 100644 (file)
@@ -1,14 +1,19 @@
 package org.jetbrains.protocolReader;
 
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
 class ObjectValueReader<T> extends ValueReader {
   private final TypeRef<T> refToType;
   private final boolean isSubtyping;
+  final String primitiveValueName;
 
-  ObjectValueReader(TypeRef<T> refToType, boolean isSubtyping) {
+  ObjectValueReader(@NotNull TypeRef<T> refToType, boolean isSubtyping, @Nullable String primitiveValueName) {
     super();
 
     this.refToType = refToType;
     this.isSubtyping = isSubtyping;
+    this.primitiveValueName = primitiveValueName == null || primitiveValueName.isEmpty() ? null : primitiveValueName;
   }
 
   TypeRef<T> getType() {
@@ -25,31 +30,35 @@ class ObjectValueReader<T> extends ValueReader {
   }
 
   @Override
-  public void appendFinishedValueTypeName(TextOutput out) {
-    out.append(refToType.getTypeClass().getCanonicalName());
+  public void appendFinishedValueTypeName(@NotNull TextOutput out) {
+    out.append(refToType.typeClass.getCanonicalName());
   }
 
   @Override
-  public void appendInternalValueTypeName(FileScope classScope, TextOutput out) {
-    out.append(classScope.getTypeImplReference(refToType.get()));
+  public void appendInternalValueTypeName(@NotNull FileScope classScope, @NotNull TextOutput out) {
+    out.append(classScope.getTypeImplReference(refToType.type));
   }
 
   @Override
-  void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, TextOutput out) {
-    refToType.get().writeInstantiateCode(scope.getRootClassScope(), subtyping, out);
+  void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, @NotNull TextOutput out) {
+    refToType.type.writeInstantiateCode(scope.getRootClassScope(), subtyping, out);
     out.append('(');
     addReaderParameter(subtyping, out);
     out.comma().append("null");
-    if (subtyping && refToType.get().getSubtypeSupport() != null) {
+    if (subtyping && refToType.type.subtypeAspect != null) {
       out.comma().append("this");
     }
     out.append(')');
   }
 
   @Override
-  public void writeArrayReadCode(ClassScope scope, boolean subtyping, TextOutput out) {
+  public void writeArrayReadCode(@NotNull ClassScope scope, boolean subtyping, @NotNull TextOutput out) {
     beginReadCall("ObjectArray", subtyping, out);
-    out.comma().append("new ").append(scope.requireFactoryGenerationAndGetName(refToType.get())).append(Util.TYPE_FACTORY_NAME_POSTFIX).append("()");
+    writeFactoryArgument(scope, out);
     out.append(')');
   }
+
+  void writeFactoryArgument(@NotNull ClassScope scope, @NotNull TextOutput out) {
+    out.comma().append("new ").append(scope.requireFactoryGenerationAndGetName(refToType.type)).append(Util.TYPE_FACTORY_NAME_POSTFIX).append("()");
+  }
 }
index e5c3db3edeaed3a87461b19055bc36895a96734b..3757bccfdf368dccae6917a0ce9ebf6dedbbb22a 100644 (file)
@@ -1,5 +1,7 @@
 package org.jetbrains.protocolReader;
 
+import org.jetbrains.annotations.NotNull;
+
 class PrimitiveValueReader extends ValueReader {
   private final String className;
   private final String readPostfix;
@@ -30,7 +32,7 @@ class PrimitiveValueReader extends ValueReader {
   }
 
   @Override
-  void writeReadCode(ClassScope methodScope, boolean subtyping, String fieldName, TextOutput out) {
+  void writeReadCode(ClassScope methodScope, boolean subtyping, String fieldName, @NotNull TextOutput out) {
     if (asRawString) {
       out.append("readRawString(");
       addReaderParameter(subtyping, out);
@@ -44,14 +46,14 @@ class PrimitiveValueReader extends ValueReader {
   }
 
   @Override
-  void appendFinishedValueTypeName(TextOutput out) {
+  void appendFinishedValueTypeName(@NotNull TextOutput out) {
     out.append(className);
   }
 
   @Override
-  public void writeArrayReadCode(ClassScope scope,
+  public void writeArrayReadCode(@NotNull ClassScope scope,
                                  boolean subtyping,
-                                 TextOutput out) {
+                                 @NotNull TextOutput out) {
     if (readPostfix.equals("String")) {
       out.append("nextList");
     }
index a8b46b87815a38c78566c6cc31cd806eb15ce8ca..7ce98776f8e28e29aefb6ea366103369b60a33c1 100644 (file)
@@ -1,5 +1,6 @@
 package org.jetbrains.protocolReader;
 
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.io.JsonReaderEx;
 
 class RawValueReader extends ValueReader {
@@ -8,7 +9,7 @@ class RawValueReader extends ValueReader {
   }
 
   @Override
-  void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, TextOutput out) {
+  void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, @NotNull TextOutput out) {
     addReaderParameter(subtyping, out);
     out.append(".subReader();").newLine();
     addReaderParameter(subtyping, out);
@@ -16,14 +17,7 @@ class RawValueReader extends ValueReader {
   }
 
   @Override
-  public void appendFinishedValueTypeName(TextOutput out) {
+  public void appendFinishedValueTypeName(@NotNull TextOutput out) {
     out.append(JsonReaderEx.class.getCanonicalName());
   }
-
-  @Override
-  void writeArrayReadCode(ClassScope scope,
-                          boolean subtyping,
-                          TextOutput out) {
-    throw new UnsupportedOperationException();
-  }
 }
index 71150f1fad7930401da7b4eb9a2552a2f1f5b780..a66f0442c9f6b60297c7768e681ac79e035f0d32 100644 (file)
@@ -108,7 +108,7 @@ public final class ReaderGenerator {
 
     Map<Class<?>, String> typeToImplClassName = new THashMap<>();
     for (TypeHandler<?> typeHandler : configuration.typeToTypeHandler.values()) {
-      typeToImplClassName.put(typeHandler.getTypeClass(), configuration.packageName + "." + configuration.className + "." + fileScope.getTypeImplShortName(typeHandler));
+      typeToImplClassName.put(typeHandler.typeClass, configuration.packageName + "." + configuration.className + "." + fileScope.getTypeImplShortName(typeHandler));
     }
     return typeToImplClassName;
   }
@@ -144,7 +144,7 @@ public final class ReaderGenerator {
         out.newLine();
       }
 
-      String originName = typeHandler.getTypeClass().getCanonicalName();
+      String originName = typeHandler.typeClass.getCanonicalName();
       out.newLine().append("private static final class ").append(globalScope.getTypeImplShortName(typeHandler)).append(Util.TYPE_FACTORY_NAME_POSTFIX).append(" extends ObjectFactory<");
       out.append(originName).append('>').openBlock();
       out.append("@Override").newLine().append("public ").append(originName).append(" read(").append(Util.JSON_READER_PARAMETER_DEF);
index 569f6cf0623a374df9a8915b90b21899a8aa37c9..eb7424926f0ae70e4b54c1b1bb679118ae017e52 100644 (file)
@@ -1,23 +1,25 @@
 package org.jetbrains.protocolReader;
 
+import org.jetbrains.annotations.NotNull;
+
 public class StringIntPairValueReader extends ValueReader {
   StringIntPairValueReader() {
     super();
   }
 
   @Override
-  void appendFinishedValueTypeName(TextOutput out) {
+  void appendFinishedValueTypeName(@NotNull TextOutput out) {
     out.append("StringIntPair");
   }
 
   @Override
-  void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, TextOutput out) {
+  void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, @NotNull TextOutput out) {
   }
 
   @Override
-  void writeArrayReadCode(ClassScope scope,
+  void writeArrayReadCode(@NotNull ClassScope scope,
                           boolean subtyping,
-                          TextOutput out) {
+                          @NotNull TextOutput out) {
     out.append("read").append("IntStringPairs").append('(');
     addReaderParameter(subtyping, out);
     out.append(')');
index 5b6278547f4de3f69753ddd32d986c38a98ae016..12ea2d964925ec80fc1cd56911901e0d692c4408 100644 (file)
@@ -18,6 +18,6 @@ abstract class SubtypeCaster {
   abstract void writeJava(TextOutput out);
 
   TypeHandler<?> getSubtypeHandler() {
-    return subtypeRef.get();
+    return subtypeRef.type;
   }
 }
\ No newline at end of file
index 77d4bd1e275fa0162a23e904deadc4f3182bdafc..f259614024ea8cc8448e7f40ba7f46e46bf6ece0 100644 (file)
@@ -104,7 +104,7 @@ public class TextOutput {
   }
 
   public TextOutput comma() {
-    return append(',').append(' ');
+    return append(',').space();
   }
 
   public TextOutput space() {
index a5577ce563c8c9a3db775669699166462ad8ea08..7b8bd880f351aa6af1b161cecbdfc6ec0febdf45 100644 (file)
@@ -1,7 +1,6 @@
 package org.jetbrains.protocolReader;
 
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 import org.jetbrains.jsonProtocol.JsonObjectBased;
 
 import java.lang.reflect.Method;
@@ -10,7 +9,7 @@ import java.util.List;
 import java.util.Map;
 
 class TypeHandler<T> {
-  private final Class<T> typeClass;
+  final Class<T> typeClass;
 
   private final List<VolatileFieldBinding> volatileFields;
 
@@ -20,7 +19,7 @@ class TypeHandler<T> {
   private final List<FieldLoader> fieldLoaders;
 
   /** Subtype aspects of the type or null */
-  private final ExistingSubtypeAspect subtypeAspect;
+  final ExistingSubtypeAspect subtypeAspect;
 
   private final boolean hasLazyFields;
 
@@ -37,15 +36,6 @@ class TypeHandler<T> {
     subtypeAspect = jsonSuperClass == null ? null : new ExistingSubtypeAspect(jsonSuperClass);
   }
 
-  public Class<T> getTypeClass() {
-    return typeClass;
-  }
-
-  @Nullable
-  public ExistingSubtypeAspect getSubtypeSupport() {
-    return subtypeAspect;
-  }
-
   public void writeInstantiateCode(@NotNull ClassScope scope, @NotNull TextOutput out) {
     writeInstantiateCode(scope, false, out);
   }
@@ -65,7 +55,7 @@ class TypeHandler<T> {
     String valueImplClassName = fileScope.getTypeImplShortName(this);
     out.append("private static final class ").append(valueImplClassName);
 
-    out.append(" implements ").append(getTypeClass().getCanonicalName()).openBlock();
+    out.append(" implements ").append(typeClass.getCanonicalName()).openBlock();
 
     if (hasLazyFields || JsonObjectBased.class.isAssignableFrom(typeClass)) {
       out.append("private ").append(Util.JSON_READER_CLASS_NAME).space().append(Util.PENDING_INPUT_READER_NAME).semi().newLine();
@@ -111,7 +101,7 @@ class TypeHandler<T> {
    * {@link org.jetbrains.jsonProtocol.JsonObjectBased#getDeferredReader()}
    */
   private void writeBaseMethods(TextOutput out) {
-    Class<?> typeClass = getTypeClass();
+    Class<?> typeClass = this.typeClass;
     Method method;
     try {
       method = typeClass.getMethod("getDeferredReader");
@@ -196,9 +186,28 @@ class TypeHandler<T> {
       out.append(operator).append(" (name");
       out.append(".equals(\"").append(fieldName).append("\"))").openBlock();
       {
+        String primitiveValueName = fieldLoader.valueReader instanceof ObjectValueReader ? ((ObjectValueReader)fieldLoader.valueReader).primitiveValueName : null;
+        if (primitiveValueName != null) {
+          out.append("if (reader.peek() == com.google.gson.stream.JsonToken.BEGIN_OBJECT)").openBlock();
+        }
         assignField(out, fieldName);
+
         fieldLoader.valueReader.writeReadCode(classScope, false, fieldName, out);
         out.semi();
+
+        if (primitiveValueName != null) {
+          out.closeBlock();
+          out.newLine().append("else").openBlock();
+
+          assignField(out, primitiveValueName + "Type");
+          out.append("reader.peek()").semi().newLine();
+
+          assignField(out, primitiveValueName);
+          out.append("reader.nextString(true)").semi();
+
+          out.closeBlock();
+        }
+
         if (stopIfAllFieldsWereRead && !isTracedStop) {
           out.newLine().append(Util.READER_NAME).append(".skipValues()").semi().newLine().append("break").semi();
         }
@@ -225,6 +234,7 @@ class TypeHandler<T> {
     out.newLine().append("while ((name = reader.nextNameOrNull()) != null)").semi();
   }
 
+  @NotNull
   private static TextOutput assignField(TextOutput out, String fieldName) {
     return out.append(FieldLoader.FIELD_PREFIX).append(fieldName).append(" = ");
   }
index 163254aef3e7078f7d27fc305cfa9bb62bfba4f4..d92e9af533cb457257f9fdbd521eaf628fcbd823 100644 (file)
@@ -2,22 +2,9 @@ package org.jetbrains.protocolReader;
 
 class TypeRef<T> {
   final Class<T> typeClass;
-  private TypeHandler<T> type;
+  TypeHandler<T> type;
 
   TypeRef(Class<T> typeClass) {
     this.typeClass = typeClass;
   }
-
-  Class<?> getTypeClass() {
-    return typeClass;
-  }
-
-  TypeHandler<T> get() {
-    return type;
-  }
-
-  void set(TypeHandler<?> type) {
-    //noinspection unchecked
-    this.type = (TypeHandler<T>)type;
-  }
 }
index 8b81b42470eda7901776e1464bd1bfb574f92e8e..ba3dba8d6e8c8273acbb0fc766363318c6e80fc3 100644 (file)
@@ -1,5 +1,7 @@
 package org.jetbrains.protocolReader;
 
+import org.jetbrains.annotations.NotNull;
+
 /**
  * A parser that accepts value of JSON field and outputs value in another form (e.g. string
  * is converted to enum constant) to serve field getters in JsonType interfaces.
@@ -9,15 +11,17 @@ abstract class ValueReader {
     return null;
   }
 
-  abstract void appendFinishedValueTypeName(TextOutput out);
+  abstract void appendFinishedValueTypeName(@NotNull TextOutput out);
 
-  void appendInternalValueTypeName(FileScope scope, TextOutput out) {
+  void appendInternalValueTypeName(@NotNull FileScope scope, @NotNull TextOutput out) {
     appendFinishedValueTypeName(out);
   }
 
-  abstract void writeReadCode(ClassScope methodScope, boolean subtyping, String fieldName, TextOutput out);
+  abstract void writeReadCode(ClassScope methodScope, boolean subtyping, String fieldName, @NotNull TextOutput out);
 
-  abstract void writeArrayReadCode(ClassScope scope, boolean subtyping, TextOutput out);
+  void writeArrayReadCode(@NotNull ClassScope scope, boolean subtyping, @NotNull TextOutput out) {
+    throw new UnsupportedOperationException();
+  }
 
   protected void beginReadCall(String readPostfix, boolean subtyping, TextOutput out) {
     out.append("read");