return promise;
}
+ @Override
void notify(@NotNull final AsyncPromise<T> child) {
switch (state) {
case PENDING:
public T get() {
return result;
}
+
+ @Override
+ void notify(@NotNull AsyncPromise<T> child) {
+ child.setResult(result);
+ }
}
\ No newline at end of file
return this;
}
}
+
+ abstract void notify(@NotNull AsyncPromise<T> child);
}
\ No newline at end of file
}
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
public State getState() {
return State.REJECTED;
}
+
+ @Override
+ void notify(@NotNull AsyncPromise<T> child) {
+ child.setError(error);
+ }
}
\ No newline at end of file
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
--- /dev/null
+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
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.jetbrains.concurrency.Promise;
-
-import java.util.List;
public interface Scope {
enum Type {
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
@Nullable
@Override
- public String getDescription() {
+ public final String getDescription() {
return description;
}
@NotNull
@Override
- public Type getType() {
+ public final Type getType() {
return type;
}
--- /dev/null
+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;
+ }
+}
import org.jetbrains.annotations.Nullable;
import org.jetbrains.concurrency.Promise;
import org.jetbrains.debugger.Variable;
+import org.jetbrains.debugger.VariablesHost;
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
*
*/
@NotNull
ThreeState hasIndexedProperties();
-
- int getCacheStamp();
}
\ No newline at end of file
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
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
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) {
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));
}
@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
boolean allowAnyPrimitiveValueAndMap() default false;
boolean optional() default false;
+
+ String primitiveValue() default "";
}
\ No newline at end of file
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;
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;
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;
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) {
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;
}
@Override
- public void appendFinishedValueTypeName(TextOutput out) {
+ public void appendFinishedValueTypeName(@NotNull TextOutput out) {
if (isList) {
out.append("java.util.List<");
componentParser.appendFinishedValueTypeName(out);
}
@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) {
- }
}
}
public ClassScope getRootClassScope() {
- if (parentClass == null) {
- return this;
- }
- else {
- return parentClass.getRootClassScope();
- }
+ return parentClass == null ? this : parentClass.getRootClassScope();
}
@Override
-// 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);
}
@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();
- }
}
}
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) {
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();
}
methodHandlerMap.put(method, methodHandler);
}
- catch (JsonProtocolModelParseException e) {
+ catch (Exception e) {
throw new JsonProtocolModelParseException("Problem with method " + method, e);
}
}
}
}
- 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));
}
return methodHandlerMap;
}
+ @NotNull
private VolatileFieldBinding allocateVolatileField(final ValueReader fieldTypeParser, boolean internalType) {
int position = volatileFields.size();
FieldTypeInfo fieldTypeInfo;
}
for (Map<Class<?>, String> base : basePackages) {
- String result = base.get(typeHandler.getTypeClass());
+ String result = base.get(typeHandler.typeClass);
if (result != null) {
return result;
}
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;
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(')');
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;
// 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);
}
}
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;
}
}
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
}
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);
}
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) {
Util.writeJavaTypeName(m.getGenericReturnType(), out);
}
else {
- out.append(scope.getTypeImplReference(objectValueParser.getType().get()));
+ out.append(scope.getTypeImplReference(objectValueParser.getType().type));
}
}
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();
- }
}
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() {
}
@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("()");
+ }
}
package org.jetbrains.protocolReader;
+import org.jetbrains.annotations.NotNull;
+
class PrimitiveValueReader extends ValueReader {
private final String className;
private final String readPostfix;
}
@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);
}
@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");
}
package org.jetbrains.protocolReader;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.io.JsonReaderEx;
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);
}
@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();
- }
}
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;
}
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);
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(')');
abstract void writeJava(TextOutput out);
TypeHandler<?> getSubtypeHandler() {
- return subtypeRef.get();
+ return subtypeRef.type;
}
}
\ No newline at end of file
}
public TextOutput comma() {
- return append(',').append(' ');
+ return append(',').space();
}
public TextOutput space() {
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import org.jetbrains.jsonProtocol.JsonObjectBased;
import java.lang.reflect.Method;
import java.util.Map;
class TypeHandler<T> {
- private final Class<T> typeClass;
+ final Class<T> typeClass;
private final List<VolatileFieldBinding> volatileFields;
private final List<FieldLoader> fieldLoaders;
/** Subtype aspects of the type or null */
- private final ExistingSubtypeAspect subtypeAspect;
+ final ExistingSubtypeAspect subtypeAspect;
private final boolean hasLazyFields;
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);
}
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();
* {@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");
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();
}
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(" = ");
}
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;
- }
}
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.
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");