Skip to content

Commit

Permalink
Merge pull request #10 from strategyobject/feature/rpc-contracts
Browse files Browse the repository at this point in the history
Rpc contracts
  • Loading branch information
kalaninja authored Feb 14, 2022
2 parents a03ef19 + edbb6af commit 1e09c79
Show file tree
Hide file tree
Showing 56 changed files with 612 additions and 169 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ subprojects {

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.2'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.2'
testImplementation 'org.assertj:assertj-core:3.22.0'
testImplementation 'org.mockito:mockito-core:3.12.4'
testImplementation 'org.mockito:mockito-inline:3.12.4'
testImplementation 'org.slf4j:slf4j-simple:1.7.32'

testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2'
}
Expand Down
2 changes: 1 addition & 1 deletion common/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
dependencies {
implementation 'org.reflections:reflections:0.10.1'
implementation 'org.reflections:reflections:0.10.2'
implementation 'com.squareup:javapoet:1.13.0'
}
6 changes: 3 additions & 3 deletions rpc/rpc-codegen/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ dependencies {
implementation project(':scale:scale-codegen')
implementation project(':transport')

compileOnly 'com.google.auto.service:auto-service-annotations:1.0'
annotationProcessor 'com.google.auto.service:auto-service:1.0'
compileOnly 'com.google.auto.service:auto-service-annotations:1.0.1'
annotationProcessor 'com.google.auto.service:auto-service:1.0.1'

implementation 'com.squareup:javapoet:1.13.0'
testImplementation 'com.google.testing.compile:compile-testing:0.19'
testImplementation 'com.google.code.gson:gson:2.8.8'
testImplementation 'com.google.code.gson:gson:2.8.9'

testCompileOnly project(':rpc:rpc-codegen')
testAnnotationProcessor project(':rpc:rpc-codegen')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.strategyobject.substrateclient.scale.codegen.ScaleAnnotationParser;
import com.strategyobject.substrateclient.scale.codegen.reader.ReaderCompositor;
import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry;
import com.strategyobject.substrateclient.transport.RpcObject;
import lombok.NonNull;
import lombok.val;
import lombok.var;
Expand Down Expand Up @@ -83,14 +84,15 @@ private MethodSpec generateDecodeMethod(ProcessorContext context, TypeName class
.addAnnotation(suppressWarnings("unchecked"))
.addModifiers(Modifier.PUBLIC)
.returns(classWildcardTyped)
.addParameter(Object.class, VALUE_ARG)
.addParameter(RpcObject.class, VALUE_ARG)
.addParameter(ArrayTypeName.of(
ParameterizedTypeName.get(
ClassName.get(DecoderPair.class),
WildcardTypeName.subtypeOf(Object.class))),
DECODERS_ARG)
.varargs(true);

shortcutIfNull(methodSpec);
addValidationRules(methodSpec);
addMethodBody(methodSpec, context);

Expand All @@ -100,10 +102,9 @@ private MethodSpec generateDecodeMethod(ProcessorContext context, TypeName class
private void addMethodBody(MethodSpec.Builder methodSpec, ProcessorContext context) throws ProcessingException {
val resultType = JavaPoet.setEachGenericParameterAs(classElement, TypeName.OBJECT);
methodSpec
.addStatement("if ($L == null) { return null; }", VALUE_ARG)
.addStatement("$1T $2L = $1T.getInstance()", RpcDecoderRegistry.class, DECODER_REGISTRY)
.addStatement("$1T $2L = $1T.getInstance()", ScaleReaderRegistry.class, SCALE_READER_REGISTRY)
.addStatement("$1T<$2T, ?> $3L = ($1T<$2T, ?>)$4L", Map.class, String.class, MAP_VAR, VALUE_ARG)
.addStatement("$T<$T, $T> $L = $L.asMap()", Map.class, String.class, RpcObject.class, MAP_VAR, VALUE_ARG)
.addStatement("$1T $2L = new $1T()", resultType, RESULT_VAR)
.beginControlFlow("try");

Expand Down Expand Up @@ -166,13 +167,8 @@ private void setScaleField(MethodSpec.Builder methodSpec,
readerCompositor.traverse(fieldType);
methodSpec
.addStatement(code
.add("$T.$L(",
ScaleUtils.class,
FROM_HEX_STRING)
.add("($T)$L.get($S), ",
String.class,
MAP_VAR,
field)
.add("$T.$L(", ScaleUtils.class, FROM_HEX_STRING)
.add("$L.get($S).asString(), ", MAP_VAR, field)
.add("($T)", ScaleReader.class)
.add(readerCode)
.add("))")
Expand Down Expand Up @@ -225,4 +221,8 @@ private void addValidationRules(MethodSpec.Builder methodSpec) {
}
}
}

private void shortcutIfNull(MethodSpec.Builder methodSpec) {
methodSpec.addStatement("if ($L.isNull()) { return null; }", VALUE_ARG);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ private MethodSpec generateEncodeMethod(ProcessorContext context, TypeName class
ENCODERS_ARG)
.varargs(true);

shortcutIfNull(methodSpec);
addValidationRules(methodSpec, context);
addMethodBody(methodSpec, context);

Expand All @@ -100,7 +101,6 @@ private MethodSpec generateEncodeMethod(ProcessorContext context, TypeName class

private void addMethodBody(MethodSpec.Builder methodSpec, ProcessorContext context) throws ProcessingException {
methodSpec
.addStatement("if ($L == null) { return null; }", SOURCE_ARG)
.addStatement("$1T $2L = $1T.getInstance()", RpcEncoderRegistry.class, ENCODER_REGISTRY)
.addStatement("$1T $2L = $1T.getInstance()", ScaleWriterRegistry.class, SCALE_WRITER_REGISTRY)
.addStatement("$1T<$2T, $3T> $4L = new $1T<>()", HashMap.class, String.class, Object.class, RESULT_VAR)
Expand Down Expand Up @@ -223,4 +223,8 @@ private void addValidationRules(MethodSpec.Builder methodSpec, ProcessorContext
}
}
}

private void shortcutIfNull(MethodSpec.Builder methodSpec) {
methodSpec.addStatement("if ($L == null) { return null; }", SOURCE_ARG);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ private CodeBlock getScaleReadCodeBlock(AnnotatedConstruct annotated,
return CodeBlock.builder()
.add("($T) (", resultType)
.add("$T.$L(", ScaleUtils.class, FROM_HEX_STRING)
.add("($T) $L, ($T) ", String.class, arg, ScaleReader.class)
.add("$L.asString(), ($T) ", arg, ScaleReader.class)
.add(readerCode)
.add("))")
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.strategyobject.substrateclient.common.codegen.ProcessingException;
import com.strategyobject.substrateclient.common.codegen.ProcessorContext;
import com.strategyobject.substrateclient.rpc.core.annotations.RpcSubscription;
import com.strategyobject.substrateclient.transport.RpcObject;
import lombok.NonNull;
import lombok.val;

Expand Down Expand Up @@ -58,7 +59,7 @@ protected void callProviderInterface(MethodSpec.Builder methodSpecBuilder,
.add("$1T<$2T, $3T> $4L = ($5L, $6L) -> { $7N.$8L($5L, ",
BiConsumer.class,
Exception.class,
Object.class,
RpcObject.class,
CALL_BACK_PROXY,
CALL_BACK_EX_ARG,
CALL_BACK_ARG,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@
import com.strategyobject.substrateclient.rpc.codegen.substitutes.TestDecodable;
import com.strategyobject.substrateclient.rpc.core.DecoderPair;
import com.strategyobject.substrateclient.rpc.core.registries.RpcDecoderRegistry;
import com.strategyobject.substrateclient.transport.RpcObject;
import lombok.val;
import org.junit.jupiter.api.Test;

import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.HashMap;

import static com.google.testing.compile.CompilationSubject.assertThat;
import static com.google.testing.compile.Compiler.javac;
Expand Down Expand Up @@ -62,23 +60,50 @@ void compilesAndDecodes() { // TODO move this test out of the project
val decoder = registry.resolve(TestDecodable.class)
.inject(DecoderPair.of(registry.resolve(String.class), null));

Object source = gson.fromJson("{\"a\":4,\"b\":\"123\",\"c\":\"some\"," +
"\"d\":[\"1\",\"2\"],\"e\":{\"a\":1,\"b\":2},\"f\":\"0x04000000\"," +
"\"g\":\"0x0c0500000002000000fdffffff\"}",
Object.class);
/*
{
"a": 4,
"b": "123",
"c": "some",
"d": [
"1",
"2"
],
"e": {
"a": null,
"b": 2
},
"f": "0x04000000",
"g": "0x0c0500000002000000fdffffff",
"h": 1.5,
}
*/
val source = RpcObject.of(new HashMap<String, RpcObject>() {{
put("a", RpcObject.of(4));
put("b", RpcObject.of("123"));
put("c", RpcObject.of("some"));
put("d", RpcObject.of(Arrays.asList(RpcObject.of("1"), RpcObject.of("2"))));
put("e", RpcObject.of(new HashMap<String, RpcObject>() {{
put("a", RpcObject.ofNull());
put("b", RpcObject.of(2));
}}));
put("f", RpcObject.of("0x04000000"));
put("g", RpcObject.of("0x0c0500000002000000fdffffff"));
put("h", RpcObject.of(1.5));
}});
val actual = decoder.decode(source);

val expected = new TestDecodable<>(4,
"123",
"some",
Arrays.asList("1", "2"),
Stream.of(
new AbstractMap.SimpleEntry<>("a", 1),
new AbstractMap.SimpleEntry<>("b", 2))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)),
new HashMap<String, Float>() {{
put("a", null);
put("b", 2f);
}},
4,
Arrays.asList(5, 2, -3));

val actual = decoder.decode(source);

Arrays.asList(5, 2, -3),
1.5f);
assertEquals(gson.toJson(expected), gson.toJson(actual));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.strategyobject.substrateclient.rpc.codegen.substitutes.TestSection;
import com.strategyobject.substrateclient.transport.ProviderInterface;
import com.strategyobject.substrateclient.transport.RpcBoolean;
import com.strategyobject.substrateclient.transport.RpcObject;
import lombok.val;
import org.junit.jupiter.api.Test;

Expand All @@ -19,7 +21,7 @@ public class RpcSectionFactoryTest {
@Test
void createsRpcSectionAndCallsMethod() throws ExecutionException, InterruptedException, RpcInterfaceInitializationException {
val expected = true;
val sendFuture = CompletableFuture.completedFuture((Object) Boolean.valueOf(expected));
val sendFuture = CompletableFuture.completedFuture((RpcObject) new RpcBoolean(expected));
val provider = mock(ProviderInterface.class);
when(provider.send(anyString(), anyList()))
.thenReturn(sendFuture);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ public class TestDecodable<T> {
private String b;
private T c;
private List<String> d;
private Map<String, Integer> e;
private Map<String, Float> e;
@Scale
private int f;
@Scale
private List<Integer> g;
private float h;
}
3 changes: 2 additions & 1 deletion rpc/rpc-core/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
dependencies {
implementation project(':common')
implementation project(':scale')
implementation project(':transport')

testImplementation 'com.google.code.gson:gson:2.8.8'
testImplementation 'com.google.code.gson:gson:2.8.9'
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.strategyobject.substrateclient.rpc.core;

import com.strategyobject.substrateclient.transport.RpcObject;

public interface RpcDecoder<T> {
T decode(Object value, DecoderPair<?>... decoders);
T decode(RpcObject value, DecoderPair<?>... decoders);

default RpcDecoder<T> inject(DecoderPair<?>... dependencies) {
return (jsonToken, decoders) -> this.decode(jsonToken, dependencies);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@
import com.google.common.base.Preconditions;
import com.strategyobject.substrateclient.rpc.core.DecoderPair;
import com.strategyobject.substrateclient.rpc.core.RpcDecoder;
import com.strategyobject.substrateclient.transport.RpcObject;

public abstract class AbstractDecoder<T> implements RpcDecoder<T> {
@Override
public final T decode(Object value, DecoderPair<?>... decoders) {
if (value == null) {
public final T decode(RpcObject value, DecoderPair<?>... decoders) {
if (value.isNull()) {
return null;
}

// TODO I am not sure should it be the first instruction of the method or not
checkArguments(value, decoders);

return decodeNonNull(value, decoders);
}

protected abstract T decodeNonNull(Object value, DecoderPair<?>[] decoders);
protected abstract T decodeNonNull(RpcObject value, DecoderPair<?>[] decoders);

protected void checkArguments(Object value, DecoderPair<?>[] decoders) {
protected void checkArguments(RpcObject value, DecoderPair<?>[] decoders) {
Preconditions.checkArgument(decoders == null || decoders.length == 0);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.strategyobject.substrateclient.rpc.core.decoders;

import com.strategyobject.substrateclient.rpc.core.DecoderPair;
import com.strategyobject.substrateclient.transport.RpcObject;

public class BooleanDecoder extends AbstractDecoder<Boolean> {
@Override
protected Boolean decodeNonNull(Object value, DecoderPair<?>[] decoders) {
return (Boolean) value;
protected Boolean decodeNonNull(RpcObject value, DecoderPair<?>[] decoders) {
return value.asBoolean();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.strategyobject.substrateclient.rpc.core.decoders;

import com.strategyobject.substrateclient.rpc.core.DecoderPair;
import com.strategyobject.substrateclient.transport.RpcObject;

public class ByteDecoder extends AbstractDecoder<Byte> {
@Override
protected Byte decodeNonNull(Object value, DecoderPair<?>[] decoders) {
return ((Double) value).byteValue();
protected Byte decodeNonNull(RpcObject value, DecoderPair<?>[] decoders) {
return value.asNumber().byteValue();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.strategyobject.substrateclient.rpc.core.decoders;

import com.strategyobject.substrateclient.rpc.core.DecoderPair;
import com.strategyobject.substrateclient.transport.RpcObject;

public class DoubleDecoder extends AbstractDecoder<Double> {
@Override
protected Double decodeNonNull(Object value, DecoderPair<?>[] decoders) {
return (Double) value;
protected Double decodeNonNull(RpcObject value, DecoderPair<?>[] decoders) {
return value.asNumber().doubleValue();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.strategyobject.substrateclient.rpc.core.decoders;

import com.strategyobject.substrateclient.rpc.core.DecoderPair;
import com.strategyobject.substrateclient.transport.RpcObject;

public class FloatDecoder extends AbstractDecoder<Float> {
@Override
protected Float decodeNonNull(Object value, DecoderPair<?>[] decoders) {
return ((Double) value).floatValue();
protected Float decodeNonNull(RpcObject value, DecoderPair<?>[] decoders) {
return value.asNumber().floatValue();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.strategyobject.substrateclient.rpc.core.decoders;

import com.strategyobject.substrateclient.rpc.core.DecoderPair;
import com.strategyobject.substrateclient.transport.RpcObject;

public class IntDecoder extends AbstractDecoder<Integer> {
@Override
protected Integer decodeNonNull(Object value, DecoderPair<?>[] decoders) {
return ((Double) value).intValue();
protected Integer decodeNonNull(RpcObject value, DecoderPair<?>[] decoders) {
return value.asNumber().intValue();
}
}
Loading

0 comments on commit 1e09c79

Please sign in to comment.