cleanup, fix WEB-14597 Breakpoints being ignored if functions called from live console

AsynPromise — don't ignore error if no rejected handler
This commit is contained in:
Vladimir Krivosheev
2015-01-07 18:27:06 +01:00
parent fb83d4983f
commit 295d3d1dd1
29 changed files with 208 additions and 346 deletions
@@ -1,14 +1,18 @@
package org.jetbrains.concurrency;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Getter;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class AsyncPromise<T> extends Promise<T> implements Getter<T> {
private static final Logger LOG = Logger.getInstance(AsyncPromise.class);
private volatile Consumer<T> done;
private volatile Consumer<Throwable> rejected;
@@ -25,6 +29,10 @@ public class AsyncPromise<T> extends Promise<T> implements Getter<T> {
@NotNull
@Override
public Promise<T> done(@NotNull Consumer<T> done) {
if (isObsolete(done)) {
return this;
}
switch (state) {
case PENDING:
break;
@@ -84,7 +92,9 @@ public class AsyncPromise<T> extends Promise<T> implements Getter<T> {
if (list != null) {
for (Consumer<T> consumer : list) {
consumer.consume(t);
if (!isObsolete(consumer)) {
consumer.consume(t);
}
}
}
}
@@ -213,6 +223,7 @@ public class AsyncPromise<T> extends Promise<T> implements Getter<T> {
return promise;
}
@Override
@NotNull
public Promise<T> processed(@NotNull final AsyncPromise<T> fulfilled) {
switch (state) {
@@ -275,11 +286,15 @@ public class AsyncPromise<T> extends Promise<T> implements Getter<T> {
Consumer<T> done = this.done;
clearHandlers();
if (done != null) {
if (done != null && !isObsolete(done)) {
done.consume(result);
}
}
static boolean isObsolete(@Nullable Consumer<?> done) {
return done instanceof ObsolescentConsumer && ((ObsolescentConsumer)done).isObsolete();
}
public void setError(@NotNull Throwable error) {
if (state != State.PENDING) {
return;
@@ -293,6 +308,9 @@ public class AsyncPromise<T> extends Promise<T> implements Getter<T> {
if (rejected != null) {
rejected.consume(error);
}
else if (!(error instanceof MessageError)) {
LOG.error(error);
}
}
private void clearHandlers() {
@@ -15,7 +15,9 @@ class DonePromise<T> extends Promise<T> implements Getter<T> {
@NotNull
@Override
public Promise<T> done(@NotNull Consumer<T> done) {
done.consume(result);
if (!AsyncPromise.isObsolete(done)) {
done.consume(result);
}
return this;
}
@@ -26,21 +28,26 @@ class DonePromise<T> extends Promise<T> implements Getter<T> {
return this;
}
@Override
public void processed(@NotNull Consumer<T> processed) {
done(processed);
}
@NotNull
@Override
public Promise<T> rejected(@NotNull Consumer<Throwable> rejected) {
return this;
}
@Override
public void processed(@NotNull Consumer<T> processed) {
processed.consume(result);
}
@NotNull
@Override
public <SUB_RESULT> Promise<SUB_RESULT> then(@NotNull Function<T, SUB_RESULT> done) {
return Promise.resolve(done.fun(result));
if (done instanceof ObsolescentFunction && ((ObsolescentFunction)done).isObsolete()) {
return Promise.reject("obsolete");
}
else {
return Promise.resolve(done.fun(result));
}
}
@NotNull
@@ -0,0 +1,7 @@
package org.jetbrains.concurrency;
import com.intellij.util.Consumer;
public interface ObsolescentConsumer<T> extends Consumer<T> {
boolean isObsolete();
}
@@ -22,7 +22,7 @@ public abstract class PromiseManager<HOST, VALUE> {
return true;
}
public abstract Promise<VALUE> load(@NotNull HOST host, Promise<VALUE> promise);
public abstract Promise<VALUE> load(@NotNull HOST host);
public final void reset(HOST host) {
fieldUpdater.set(host, null);
@@ -52,6 +52,7 @@ public abstract class PromiseManager<HOST, VALUE> {
return getOrCreateAsyncResult(host, checkFreshness, true);
}
@NotNull
private Promise<VALUE> getOrCreateAsyncResult(HOST host, boolean checkFreshness, boolean load) {
Promise<VALUE> promise = fieldUpdater.get(host);
if (promise == null) {
@@ -89,14 +90,14 @@ public abstract class PromiseManager<HOST, VALUE> {
return getPromise(host, load, promise);
}
@NotNull
private Promise<VALUE> getPromise(HOST host, boolean load, Promise<VALUE> promise) {
if (load) {
Promise<VALUE> effectivePromise = load(host, promise);
if (effectivePromise != promise) {
((AsyncPromise<VALUE>)effectivePromise).notify((AsyncPromise<VALUE>)promise);
}
return effectivePromise;
if (!load) {
return promise;
}
return promise;
Promise<VALUE> effectivePromise = load(host);
((AsyncPromise<VALUE>)effectivePromise).notify((AsyncPromise<VALUE>)promise);
return effectivePromise;
}
}
@@ -20,7 +20,7 @@ public abstract class DeclarativeScope<VALUE_LOADER extends ValueManager> extend
@NotNull
@Override
public Promise<List<Variable>> load(@NotNull DeclarativeScope host, @NotNull Promise<List<Variable>> promise) {
public Promise<List<Variable>> load(@NotNull DeclarativeScope host) {
//noinspection unchecked
return host.loadVariables();
}
@@ -11,18 +11,20 @@ import java.util.Map;
* of suspended process, but may also be detached from any stack frame
*/
public interface EvaluateContext {
/**
* Evaluates an arbitrary {@code expression} in the particular context.
* Previously loaded {@link org.jetbrains.debugger.values.ObjectValue}s can be addressed from the expression if listed in
* additionalContext parameter.
*/
@NotNull
Promise<EvaluateResult> evaluate(@NotNull String expression, @Nullable Map<String, EvaluateContextAdditionalParameter> additionalContext);
Promise<EvaluateResult> evaluate(@NotNull String expression, @Nullable Map<String, EvaluateContextAdditionalParameter> additionalContext, boolean enableBreak);
@NotNull
Promise<EvaluateResult> evaluate(@NotNull String expression);
@NotNull
Promise<EvaluateResult> evaluate(@NotNull String expression, boolean enableBreak);
/**
* optional to implement, some protocols, WIP for example, require you to release remote objects
*/
@@ -17,7 +17,13 @@ public abstract class EvaluateContextBase<VALUE_MANAGER extends ValueManager> im
@NotNull
@Override
public Promise<EvaluateResult> evaluate(@NotNull String expression) {
return evaluate(expression, null);
return evaluate(expression, null, false);
}
@NotNull
@Override
public Promise<EvaluateResult> evaluate(@NotNull String expression, boolean enableBreak) {
return evaluate(expression, null, true);
}
@NotNull
@@ -32,7 +38,7 @@ public abstract class EvaluateContextBase<VALUE_MANAGER extends ValueManager> im
@NotNull
@Override
public abstract Promise<EvaluateResult> evaluate(@NotNull String expression, @Nullable Map<String, EvaluateContextAdditionalParameter> additionalContext);
public abstract Promise<EvaluateResult> evaluate(@NotNull String expression, @Nullable Map<String, EvaluateContextAdditionalParameter> additionalContext, boolean enableBreak);
@NotNull
public final VALUE_MANAGER getValueManager() {
@@ -13,7 +13,7 @@ public abstract class ScriptManagerBase<SCRIPT extends ScriptBase> implements Sc
@SuppressWarnings("unchecked")
private final PromiseManager<ScriptBase, String> scriptSourceLoader = new PromiseManager<ScriptBase, String>(ScriptBase.class) {
@Override
public Promise<String> load(@NotNull ScriptBase script, @NotNull Promise<String> result) {
public Promise<String> load(@NotNull ScriptBase script) {
//noinspection unchecked
return loadScriptSource((SCRIPT)script);
}
@@ -31,13 +31,14 @@ public final class ValueModifierUtil {
@NotNull String selfName) {
StringBuilder builder = new StringBuilder(selfName);
appendName(builder, variable.getName(), false);
return evaluateContext.evaluate(builder.toString(), Collections.singletonMap(selfName, host)).then(new Function<EvaluateResult, Value>() {
@Override
public Value fun(EvaluateResult result) {
variable.setValue(result.value);
return result.value;
}
});
return evaluateContext.evaluate(builder.toString(), Collections.singletonMap(selfName, host), false)
.then(new Function<EvaluateResult, Value>() {
@Override
public Value fun(EvaluateResult result) {
variable.setValue(result.value);
return result.value;
}
});
}
public static String propertyNamesToString(List<String> list, boolean quotedAware) {
@@ -20,7 +20,7 @@ public abstract class ObjectValueBase<VALUE_LOADER extends ValueManager> extends
}
@Override
public Promise<List<Variable>> load(@NotNull ObjectValueBase host, @NotNull Promise<List<Variable>> promise) {
public Promise<List<Variable>> load(@NotNull ObjectValueBase host) {
if (host.valueManager.isObsolete()) {
return ValueManager.reject();
}
@@ -1,11 +1,13 @@
package org.jetbrains.debugger;
import com.intellij.util.PairConsumer;
import com.intellij.util.Consumer;
import com.intellij.xdebugger.frame.XCompositeNode;
import com.intellij.xdebugger.frame.XValueChildrenList;
import com.intellij.xdebugger.frame.XValueGroup;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.concurrency.Promise;
import org.jetbrains.debugger.values.FunctionValue;
import org.jetbrains.rpc.CommandProcessor;
import java.util.Arrays;
@@ -21,12 +23,13 @@ class FunctionScopesValueGroup extends XValueGroup {
}
@Override
public void computeChildren(@NotNull XCompositeNode node) {
public void computeChildren(@NotNull final XCompositeNode node) {
node.setAlreadySorted(true);
ObsolescentAsyncResults.consume(value.resolve(), node, new PairConsumer<FunctionValue, XCompositeNode>() {
value.resolve()
.done(new ValueNodeConsumer<FunctionValue>(node) {
@Override
public void consume(FunctionValue value, XCompositeNode node) {
public void consume(FunctionValue value) {
Scope[] scopes = value.getScopes();
if (scopes == null || scopes.length == 0) {
node.addChildren(XValueChildrenList.EMPTY, true);
@@ -35,6 +38,15 @@ class FunctionScopesValueGroup extends XValueGroup {
ScopeVariablesGroup.createAndAddScopeList(node, Arrays.asList(scopes), variableContext, null);
}
}
})
.rejected(new Consumer<Throwable>() {
@Override
public void consume(Throwable error) {
if (!(error instanceof Promise.MessageError)) {
CommandProcessor.LOG.error(error);
}
node.setErrorMessage(error.getMessage());
}
});
}
}
@@ -1,55 +0,0 @@
package org.jetbrains.debugger;
import com.intellij.openapi.util.AsyncResult;
import com.intellij.util.Consumer;
import com.intellij.util.PairConsumer;
import com.intellij.xdebugger.Obsolescent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.concurrency.Promise;
public final class ObsolescentAsyncResults {
@NotNull
public static <T> AsyncResult<T> consume(@NotNull final AsyncResult<T> result,
@NotNull final Obsolescent obsolescent,
@NotNull final Consumer<T> consumer) {
result.doWhenDone(new Runnable() {
@Override
public void run() {
if (!obsolescent.isObsolete()) {
consumer.consume(result.getResult());
}
}
});
return result;
}
@NotNull
public static <O extends Obsolescent, T> AsyncResult<T> consume(@NotNull final AsyncResult<T> result,
@NotNull final O obsolescent,
@NotNull final PairConsumer<T, O> consumer) {
result.doWhenDone(new Runnable() {
@Override
public void run() {
if (!obsolescent.isObsolete()) {
consumer.consume(result.getResult(), obsolescent);
}
}
});
return result;
}
@NotNull
public static <O extends Obsolescent, T> Promise<T> consume(@NotNull final Promise<T> promise,
@NotNull final O obsolescent,
@NotNull final PairConsumer<T, O> consumer) {
promise.done(new Consumer<T>() {
@Override
public void consume(T result) {
if (!obsolescent.isObsolete()) {
consumer.consume(result, obsolescent);
}
}
});
return promise;
}
}
@@ -0,0 +1,18 @@
package org.jetbrains.debugger;
import com.intellij.xdebugger.Obsolescent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.concurrency.ObsolescentConsumer;
public abstract class ValueNodeConsumer<T> implements ObsolescentConsumer<T> {
private final Obsolescent node;
protected ValueNodeConsumer(@NotNull Obsolescent node) {
this.node = node;
}
@Override
public final boolean isObsolete() {
return node.isObsolete();
}
}
@@ -8,7 +8,6 @@ import com.intellij.pom.Navigatable;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.util.Consumer;
import com.intellij.util.PairConsumer;
import com.intellij.util.SmartList;
import com.intellij.util.ThreeState;
import com.intellij.xdebugger.XSourcePositionWrapper;
@@ -99,7 +98,7 @@ public final class VariableView extends XNamedValue implements VariableContext {
node.setPresentation(icon, null, valueString, true);
}
else {
context.getEvaluateContext().evaluate("a.length", Collections.<String, EvaluateContextAdditionalParameter>singletonMap("a", value))
context.getEvaluateContext().evaluate("a.length", Collections.<String, EvaluateContextAdditionalParameter>singletonMap("a", value), false)
.done(new Consumer<EvaluateResult>() {
@Override
public void consume(EvaluateResult result) {
@@ -383,31 +382,32 @@ public final class VariableView extends XNamedValue implements VariableContext {
}
@NotNull
private Promise<List<Variable>> computeNamedProperties(@NotNull final ObjectValue value, @NotNull XCompositeNode node, final boolean isLastChildren) {
return ObsolescentAsyncResults.consume(value.getProperties(), node, new PairConsumer<List<Variable>, XCompositeNode>() {
@Override
public void consume(List<Variable> variables, XCompositeNode node) {
if (value.getType() == ValueType.ARRAY && !(value instanceof ArrayValue)) {
computeArrayRanges(variables, node);
return;
}
private Promise<List<Variable>> computeNamedProperties(@NotNull final ObjectValue value, @NotNull final XCompositeNode node, final boolean isLastChildren) {
return value.getProperties()
.done(new ValueNodeConsumer<List<Variable>>(node) {
@Override
public void consume(List<Variable> variables) {
if (value.getType() == ValueType.ARRAY && !(value instanceof ArrayValue)) {
computeArrayRanges(variables, node);
return;
}
FunctionValue functionValue = value instanceof FunctionValue ? (FunctionValue)value : null;
if (functionValue != null && functionValue.hasScopes() == ThreeState.NO) {
functionValue = null;
}
FunctionValue functionValue = value instanceof FunctionValue ? (FunctionValue)value : null;
if (functionValue != null && functionValue.hasScopes() == ThreeState.NO) {
functionValue = null;
}
remainingChildren = Variables.sortFilterAndAddValueList(variables, node, VariableView.this, XCompositeNode.MAX_CHILDREN_TO_SHOW, isLastChildren && functionValue == null);
if (remainingChildren != null) {
remainingChildrenOffset = XCompositeNode.MAX_CHILDREN_TO_SHOW;
}
remainingChildren = Variables.sortFilterAndAddValueList(variables, node, VariableView.this, XCompositeNode.MAX_CHILDREN_TO_SHOW, isLastChildren && functionValue == null);
if (remainingChildren != null) {
remainingChildrenOffset = XCompositeNode.MAX_CHILDREN_TO_SHOW;
}
if (functionValue != null) {
// we pass context as variable context instead of this variable value - we cannot watch function scopes variables, so, this variable name doesn't matter
node.addChildren(XValueChildrenList.bottomGroup(new FunctionScopesValueGroup(functionValue, context)), isLastChildren);
if (functionValue != null) {
// we pass context as variable context instead of this variable value - we cannot watch function scopes variables, so, this variable name doesn't matter
node.addChildren(XValueChildrenList.bottomGroup(new FunctionScopesValueGroup(functionValue, context)), isLastChildren);
}
}
}
});
});
}
private void computeArrayRanges(@NotNull List<Variable> properties, @NotNull XCompositeNode node) {
@@ -228,7 +228,7 @@ public final class JsonReaderEx implements Closeable {
* Consumes the next token from the JSON stream and asserts that it is the
* beginning of a new object.
*/
public void beginObject() {
public JsonReaderEx beginObject() {
int p = peeked;
if (p == PEEKED_NONE) {
p = doPeek();
@@ -240,6 +240,7 @@ public final class JsonReaderEx implements Closeable {
else {
throw createParseError("Expected BEGIN_OBJECT but was " + peek());
}
return this;
}
/**
@@ -1,19 +0,0 @@
// 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.jsonProtocol;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* For field-reading method specifies its type as {@code nullable}; it means
* that JSON structure may have null value for a corresponding property.
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonNullable {
}
@@ -24,76 +24,19 @@ public final class JsonReaders {
}
}
public static String readString(JsonReaderEx reader, String fieldName) {
checkIsNull(reader, fieldName);
return reader.nextString();
}
public static String readRawString(JsonReaderEx reader) {
return reader.nextString(true);
}
public static Object readRawStringOrMap(JsonReaderEx reader) {
if (reader.peek() == JsonToken.BEGIN_OBJECT) {
return readMap(reader, null);
return readMap(reader);
}
else {
return reader.nextString(true);
}
}
public static String readNullableString(JsonReaderEx reader) {
if (reader.peek() == JsonToken.NULL) {
reader.skipValue();
return null;
}
return reader.nextString();
}
public static boolean readBoolean(JsonReaderEx reader, String fieldName) {
checkIsNull(reader, fieldName);
return reader.nextBoolean();
}
public static boolean readNullableBoolean(JsonReaderEx reader) {
if (reader.peek() == JsonToken.NULL) {
reader.skipValue();
return false;
}
return reader.nextBoolean();
}
public static int readInt(JsonReaderEx reader, String fieldName) {
checkIsNull(reader, fieldName);
return reader.nextInt();
}
public static int readNullableInt(JsonReaderEx reader) {
if (reader.peek() == JsonToken.NULL) {
reader.skipValue();
return -1;
}
return reader.nextInt();
}
public static long readLong(JsonReaderEx reader, String fieldName) {
checkIsNull(reader, fieldName);
return reader.nextLong();
}
public static double readDouble(JsonReaderEx reader, String fieldName) {
checkIsNull(reader, fieldName);
return reader.nextDouble();
}
public static long readNullableLong(JsonReaderEx reader) {
if (reader.peek() == JsonToken.NULL) {
reader.skipValue();
return -1;
}
return reader.nextLong();
}
public static <T extends Enum<T>> T readEnum(JsonReaderEx reader, String fieldName, Class<T> enumClass) {
checkIsNull(reader, fieldName);
try {
@@ -133,7 +76,7 @@ public final class JsonReaders {
return convertRawEnumName(reader.nextString());
}
public static <T extends Enum<T>> T readNullableEnum(JsonReaderEx reader, Class<T> enumClass) {
public static <T extends Enum<T>> T readEnum(JsonReaderEx reader, Class<T> enumClass) {
if (reader.peek() == JsonToken.NULL) {
reader.skipValue();
return null;
@@ -141,26 +84,16 @@ public final class JsonReaders {
return Enum.valueOf(enumClass, readEnumName(reader));
}
public static <T> List<T> readObjectArray(JsonReaderEx reader, String fieldName, ObjectFactory<T> factory, boolean nullable) {
public static <T> List<T> readObjectArray(JsonReaderEx reader, ObjectFactory<T> factory) {
if (reader.peek() == JsonToken.NULL) {
if (nullable) {
reader.skipValue();
return null;
}
else {
checkIsNull(reader, fieldName);
}
reader.skipValue();
return null;
}
reader.beginArray();
if (!reader.hasNext()) {
reader.endArray();
if (nullable) {
return null;
}
else {
return Collections.emptyList();
}
return Collections.emptyList();
}
List<T> result = new ArrayList<T>();
@@ -172,8 +105,7 @@ public final class JsonReaders {
return result;
}
public static Map<?, ?> readMap(JsonReaderEx reader, String fieldName) {
checkIsNull(reader, fieldName);
public static Map<?, ?> readMap(JsonReaderEx reader) {
reader.beginObject();
if (!reader.hasNext()) {
reader.endObject();
@@ -321,10 +253,6 @@ public final class JsonReaders {
return result;
}
public static JsonReaderEx createReader(CharSequence string) {
return new JsonReaderEx(string);
}
public static boolean findBooleanField(String name, JsonReaderEx reader) {
reader.beginObject();
while (reader.hasNext()) {
@@ -4,8 +4,8 @@ class ArrayReader extends ValueReader {
private final ValueReader componentParser;
private final boolean isList;
ArrayReader(ValueReader componentParser, boolean isList, boolean nullable) {
super(nullable);
ArrayReader(ValueReader componentParser, boolean isList) {
super();
this.componentParser = componentParser;
this.isList = isList;
@@ -31,13 +31,10 @@ class ArrayReader extends ValueReader {
@Override
void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, TextOutput out) {
componentParser.writeArrayReadCode(scope, subtyping, isNullable(), fieldName, out);
componentParser.writeArrayReadCode(scope, subtyping, out);
}
@Override
void writeArrayReadCode(ClassScope scope,
boolean subtyping,
boolean nullable,
String fieldName, TextOutput out) {
void writeArrayReadCode(ClassScope scope, boolean subtyping, TextOutput out) {
}
}
@@ -5,14 +5,14 @@
package org.jetbrains.protocolReader;
class EnumReader<T extends Enum<T>> extends ValueReader {
public static <T extends Enum<T>> EnumReader<T> create(Class<T> enumTypeClass, boolean isNullable) {
return new EnumReader<>(enumTypeClass, isNullable);
public static <T extends Enum<T>> EnumReader<T> create(Class<T> enumTypeClass) {
return new EnumReader<>(enumTypeClass);
}
private final Class<T> enumClass;
private EnumReader(Class<T> enumClass, boolean nullable) {
super(nullable);
private EnumReader(Class<T> enumClass) {
super();
this.enumClass = enumClass;
}
@@ -23,15 +23,14 @@ class EnumReader<T extends Enum<T>> extends ValueReader {
@Override
void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, TextOutput out) {
beginReadCall("Enum", subtyping, out, fieldName);
beginReadCall("Enum", subtyping, out);
out.comma().append(enumClass.getCanonicalName()).append(".class").append(')');
}
@Override
void writeArrayReadCode(ClassScope scope,
boolean subtyping,
boolean nullable,
String fieldName, TextOutput out) {
TextOutput out) {
throw new UnsupportedOperationException();
}
}
@@ -2,11 +2,11 @@ package org.jetbrains.protocolReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jsonProtocol.JsonField;
import org.jetbrains.jsonProtocol.JsonNullable;
import org.jetbrains.jsonProtocol.JsonOptionalField;
import org.jetbrains.jsonProtocol.JsonSubtypeCasting;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
@@ -63,24 +63,23 @@ final class FieldProcessor<T> {
private MethodHandler processFieldGetterMethod(@NotNull Method method, @NotNull String fieldName) {
Type genericReturnType = method.getGenericReturnType();
boolean nullable;
if (method.getAnnotation(JsonNullable.class) != null) {
nullable = true;
}
else if (genericReturnType == String.class || genericReturnType == Enum.class || (genericReturnType instanceof Class && !((Class)genericReturnType).isPrimitive())) {
JsonField jsonField = method.getAnnotation(JsonField.class);
if (jsonField != null) {
nullable = jsonField.optional() && !jsonField.allowAnyPrimitiveValue() && !jsonField.allowAnyPrimitiveValueAndMap();
}
else {
nullable = method.getAnnotation(JsonOptionalField.class) != null;
}
boolean addNotNullAnnotation;
boolean isPrimitive = genericReturnType instanceof Class ? ((Class)genericReturnType).isPrimitive() : !(genericReturnType instanceof ParameterizedType);
if (isPrimitive) {
addNotNullAnnotation = false;
}
else {
nullable = false;
JsonField jsonField = method.getAnnotation(JsonField.class);
if (jsonField != null) {
addNotNullAnnotation = !jsonField.optional() && !jsonField.allowAnyPrimitiveValue() && !jsonField.allowAnyPrimitiveValueAndMap();
}
else {
addNotNullAnnotation = method.getAnnotation(JsonOptionalField.class) == null;
}
}
ValueReader fieldTypeParser = reader.getFieldTypeParser(genericReturnType, nullable, false, method);
ValueReader fieldTypeParser = reader.getFieldTypeParser(genericReturnType, false, method);
if (fieldTypeParser != InterfaceReader.VOID_PARSER) {
fieldLoaders.add(new FieldLoader(fieldName, fieldTypeParser));
}
@@ -89,7 +88,7 @@ final class FieldProcessor<T> {
return new MethodHandler() {
@Override
void writeMethodImplementationJava(@NotNull ClassScope scope, @NotNull Method method, @NotNull TextOutput out) {
if (!nullable) {
if (addNotNullAnnotation) {
out.append("@NotNull").newLine();
}
writeMethodDeclarationJava(out, method);
@@ -103,7 +102,7 @@ final class FieldProcessor<T> {
}
private MethodHandler processManualSubtypeMethod(final Method m, JsonSubtypeCasting jsonSubtypeCaseAnn) {
ValueReader fieldTypeParser = reader.getFieldTypeParser(m.getGenericReturnType(), false, !jsonSubtypeCaseAnn.reinterpret(), null);
ValueReader fieldTypeParser = reader.getFieldTypeParser(m.getGenericReturnType(), !jsonSubtypeCaseAnn.reinterpret(), null);
VolatileFieldBinding fieldInfo = allocateVolatileField(fieldTypeParser, true);
LazyCachedMethodHandler handler = new LazyCachedMethodHandler(fieldTypeParser, fieldInfo);
ObjectValueReader<?> parserAsObjectValueParser = fieldTypeParser.asJsonTypeParser();
@@ -18,19 +18,16 @@ class InterfaceReader {
private static final PrimitiveValueReader LONG_PARSER = new PrimitiveValueReader("long", "-1");
private static final PrimitiveValueReader INTEGER_PARSER = new PrimitiveValueReader("int", "-1");
private static final PrimitiveValueReader NULLABLE_INTEGER_PARSER = new PrimitiveValueReader("int", "-1", true, false);
private static final PrimitiveValueReader BOOLEAN_PARSER = new PrimitiveValueReader("boolean");
private static final PrimitiveValueReader FLOAT_PARSER = new PrimitiveValueReader("float");
private static final PrimitiveValueReader NUMBER_PARSER = new PrimitiveValueReader("double");
private static final PrimitiveValueReader NULLABLE_NUMBER_PARSER = new PrimitiveValueReader("double", true);
private static final PrimitiveValueReader STRING_PARSER = new PrimitiveValueReader("String");
private static final PrimitiveValueReader NULLABLE_STRING_PARSER = new PrimitiveValueReader("String", true);
private static final PrimitiveValueReader RAW_STRING_PARSER = new PrimitiveValueReader("String", null, false, true);
private static final PrimitiveValueReader RAW_STRING_OR_MAP_PARSER = new PrimitiveValueReader("Object", null, false, true) {
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) {
out.append("readRawStringOrMap(");
@@ -40,14 +37,12 @@ class InterfaceReader {
};
private static final RawValueReader JSON_PARSER = new RawValueReader(false);
private static final RawValueReader NULLABLE_JSON_PARSER = new RawValueReader(true);
private static final MapReader MAP_PARSER = new MapReader(false);
private static final MapReader NULLABLE_MAP_PARSER = new MapReader(true);
private static final StringIntPairValueReader STRING_INT_PAIR_PARSER = new StringIntPairValueReader();
final static ValueReader VOID_PARSER = new ValueReader(true) {
final static ValueReader VOID_PARSER = new ValueReader() {
@Override
public void appendFinishedValueTypeName(TextOutput out) {
out.append("void");
@@ -59,7 +54,7 @@ class InterfaceReader {
}
@Override
void writeArrayReadCode(ClassScope scope, boolean subtyping, boolean nullable, String fieldName, TextOutput out) {
void writeArrayReadCode(ClassScope scope, boolean subtyping, TextOutput out) {
throw new UnsupportedOperationException();
}
};
@@ -175,68 +170,59 @@ class InterfaceReader {
fields.lazyRead);
}
ValueReader getFieldTypeParser(Type type, boolean declaredNullable, boolean isSubtyping, @Nullable Method method) {
ValueReader getFieldTypeParser(Type type, boolean isSubtyping, @Nullable Method method) {
if (type instanceof Class) {
Class<?> typeClass = (Class<?>)type;
if (type == Long.TYPE) {
nullableIsNotSupported(declaredNullable);
return LONG_PARSER;
}
else if (type == Integer.TYPE) {
return declaredNullable ? NULLABLE_INTEGER_PARSER : INTEGER_PARSER;
return INTEGER_PARSER;
}
else if (type == Boolean.TYPE) {
nullableIsNotSupported(declaredNullable);
return BOOLEAN_PARSER;
}
else if (type == Float.TYPE) {
nullableIsNotSupported(declaredNullable);
return FLOAT_PARSER;
}
else if (type == Number.class || type == Double.TYPE) {
return declaredNullable ? NULLABLE_NUMBER_PARSER : NUMBER_PARSER;
return NUMBER_PARSER;
}
else if (type == Void.TYPE) {
nullableIsNotSupported(declaredNullable);
return VOID_PARSER;
}
else if (type == String.class) {
if (declaredNullable) {
return NULLABLE_STRING_PARSER;
}
else {
if (method != null) {
JsonField jsonField = method.getAnnotation(JsonField.class);
if (jsonField != null && jsonField.allowAnyPrimitiveValue()) {
return RAW_STRING_PARSER;
}
if (method != null) {
JsonField jsonField = method.getAnnotation(JsonField.class);
if (jsonField != null && jsonField.allowAnyPrimitiveValue()) {
return RAW_STRING_PARSER;
}
return STRING_PARSER;
}
return STRING_PARSER;
}
else if (type == Object.class) {
return RAW_STRING_OR_MAP_PARSER;
}
else if (type == JsonReaderEx.class) {
return declaredNullable ? NULLABLE_JSON_PARSER : JSON_PARSER;
return JSON_PARSER;
}
else if (type == Map.class) {
return declaredNullable ? NULLABLE_MAP_PARSER : MAP_PARSER;
return MAP_PARSER;
}
else if (type == StringIntPair.class) {
return STRING_INT_PAIR_PARSER;
}
else if (typeClass.isArray()) {
return new ArrayReader(getFieldTypeParser(typeClass.getComponentType(), false, false, null), false,
declaredNullable);
return new ArrayReader(getFieldTypeParser(typeClass.getComponentType(), false, null), false
);
}
else if (typeClass.isEnum()) {
//noinspection unchecked
return EnumReader.create((Class<RetentionPolicy>)typeClass, declaredNullable);
return EnumReader.create((Class<RetentionPolicy>)typeClass);
}
TypeRef<?> ref = getTypeRef(typeClass);
if (ref != null) {
return createJsonParser(ref, declaredNullable, isSubtyping);
return createJsonParser(ref, isSubtyping);
}
throw new JsonProtocolModelParseException("Method return type " + type + " (simple class) not supported");
}
@@ -250,10 +236,10 @@ class InterfaceReader {
argumentType = wildcard.getUpperBounds()[0];
}
}
return new ArrayReader(getFieldTypeParser(argumentType, false, false, method), true, declaredNullable);
return new ArrayReader(getFieldTypeParser(argumentType, false, method), true);
}
else if (parameterizedType.getRawType() == Map.class) {
return declaredNullable ? NULLABLE_MAP_PARSER : MAP_PARSER;
return MAP_PARSER;
}
else {
throw new JsonProtocolModelParseException("Method return type " + type + " (generic) not supported");
@@ -264,14 +250,8 @@ class InterfaceReader {
}
}
private static void nullableIsNotSupported(boolean declaredNullable) {
if (declaredNullable) {
throw new JsonProtocolModelParseException("The type cannot be declared nullable");
}
}
private static <T> ObjectValueReader<T> createJsonParser(TypeRef<T> type, boolean isNullable, boolean isSubtyping) {
return new ObjectValueReader<>(type, isNullable, isSubtyping);
private static <T> ObjectValueReader<T> createJsonParser(TypeRef<T> type, boolean isSubtyping) {
return new ObjectValueReader<>(type, isSubtyping);
}
<T> TypeRef<T> getTypeRef(Class<T> typeClass) {
@@ -2,7 +2,7 @@ package org.jetbrains.protocolReader;
public class MapReader extends ValueReader {
MapReader(boolean nullable) {
super(nullable);
super();
}
@Override
@@ -12,15 +12,14 @@ public class MapReader extends ValueReader {
@Override
void writeReadCode(ClassScope scope, boolean subtyping, String fieldName, TextOutput out) {
beginReadCall("Map", subtyping, out, fieldName);
beginReadCall("Map", subtyping, out);
out.append(')');
}
@Override
void writeArrayReadCode(ClassScope scope,
boolean subtyping,
boolean nullable,
String fieldName, TextOutput out) {
TextOutput out) {
throw new UnsupportedOperationException();
}
}
@@ -1,15 +1,11 @@
// 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;
class ObjectValueReader<T> extends ValueReader {
private final TypeRef<T> refToType;
private final boolean isSubtyping;
ObjectValueReader(TypeRef<T> refToType, boolean nullable, boolean isSubtyping) {
super(nullable);
ObjectValueReader(TypeRef<T> refToType, boolean isSubtyping) {
super();
this.refToType = refToType;
this.isSubtyping = isSubtyping;
@@ -51,9 +47,9 @@ class ObjectValueReader<T> extends ValueReader {
}
@Override
public void writeArrayReadCode(ClassScope scope, boolean subtyping, boolean nullable, String fieldName, TextOutput out) {
beginReadCall("ObjectArray", subtyping, out, fieldName);
public void writeArrayReadCode(ClassScope scope, boolean subtyping, TextOutput out) {
beginReadCall("ObjectArray", subtyping, out);
out.comma().append("new ").append(scope.requireFactoryGenerationAndGetName(refToType.get())).append(Util.TYPE_FACTORY_NAME_POSTFIX).append("()");
out.comma().append(nullable).append(')');
out.append(')');
}
}
@@ -8,19 +8,15 @@ class PrimitiveValueReader extends ValueReader {
private final boolean asRawString;
PrimitiveValueReader(String name) {
this(name, false);
}
PrimitiveValueReader(String name, boolean nullable) {
this(name, null, nullable, false);
this(name, null, false);
}
PrimitiveValueReader(String name, String defaultValue) {
this(name, defaultValue, false, false);
this(name, defaultValue, false);
}
public PrimitiveValueReader(String name, String defaultValue, boolean nullable, boolean asRawString) {
super(nullable);
public PrimitiveValueReader(String name, String defaultValue, boolean asRawString) {
super();
this.defaultValue = defaultValue;
this.asRawString = asRawString;
@@ -55,8 +51,7 @@ class PrimitiveValueReader extends ValueReader {
@Override
public void writeArrayReadCode(ClassScope scope,
boolean subtyping,
boolean nullable,
String fieldName, TextOutput out) {
TextOutput out) {
if (readPostfix.equals("String")) {
out.append("nextList");
}
@@ -4,7 +4,7 @@ import org.jetbrains.io.JsonReaderEx;
class RawValueReader extends ValueReader {
RawValueReader(boolean nullable) {
super(nullable);
super();
}
@Override
@@ -23,8 +23,7 @@ class RawValueReader extends ValueReader {
@Override
void writeArrayReadCode(ClassScope scope,
boolean subtyping,
boolean nullable,
String fieldName, TextOutput out) {
TextOutput out) {
throw new UnsupportedOperationException();
}
}
@@ -28,7 +28,7 @@ class ReadDelegate {
out.openBlock();
out.append("return ");
if (isList) {
out.append("readObjectArray(").append(Util.READER_NAME).append(", null, new ").append(scope.requireFactoryGenerationAndGetName(typeHandler)).append(Util.TYPE_FACTORY_NAME_POSTFIX).append("()").append(", false)");
out.append("readObjectArray(").append(Util.READER_NAME).append(", new ").append(scope.requireFactoryGenerationAndGetName(typeHandler)).append(Util.TYPE_FACTORY_NAME_POSTFIX).append("()").append(")");
}
else {
typeHandler.writeInstantiateCode(scope, out);
@@ -2,7 +2,7 @@ package org.jetbrains.protocolReader;
public class StringIntPairValueReader extends ValueReader {
StringIntPairValueReader() {
super(false);
super();
}
@Override
@@ -17,8 +17,7 @@ public class StringIntPairValueReader extends ValueReader {
@Override
void writeArrayReadCode(ClassScope scope,
boolean subtyping,
boolean nullable,
String fieldName, TextOutput out) {
TextOutput out) {
out.append("read").append("IntStringPairs").append('(');
addReaderParameter(subtyping, out);
out.append(')');
@@ -152,8 +152,7 @@ class TypeHandler<T> {
else {
out.append("if (name == null)").openBlock();
{
out.append("reader.beginObject()").semi();
out.newLine().append("if (reader.hasNext())").openBlock();
out.append("if (reader.beginObject().hasNext())").openBlock();
{
out.append("name = reader.nextName()").semi();
}
@@ -1,18 +1,10 @@
package org.jetbrains.protocolReader;
import org.jetbrains.annotations.Nullable;
/**
* 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.
*/
abstract class ValueReader {
private final boolean nullable;
protected ValueReader(boolean nullable) {
this.nullable = nullable;
}
public ObjectValueReader asJsonTypeParser() {
return null;
}
@@ -25,31 +17,12 @@ abstract class ValueReader {
abstract void writeReadCode(ClassScope methodScope, boolean subtyping, String fieldName, TextOutput out);
public boolean isNullable() {
return nullable;
}
abstract void writeArrayReadCode(ClassScope scope, boolean subtyping, TextOutput out);
abstract void writeArrayReadCode(ClassScope scope, boolean subtyping, boolean nullable, String fieldName, TextOutput out);
protected void beginReadCall(String readPostfix, boolean subtyping, TextOutput out, @Nullable String fieldName) {
protected void beginReadCall(String readPostfix, boolean subtyping, TextOutput out) {
out.append("read");
if (isNullable()) {
out.append("Nullable");
}
out.append(readPostfix).append('(');
addReaderParameter(subtyping, out);
if (!isNullable()) {
out.comma();
if (subtyping) {
out.append("null");
}
else if (fieldName == null) {
out.append("name");
}
else {
out.quote(fieldName);
}
}
}
protected static void addReaderParameter(boolean subtyping, TextOutput out) {