Skip to content

Commit

Permalink
implement rpc codec
Browse files Browse the repository at this point in the history
There is added code generation for RPC data transfer objects: RpcEncoderProcessor, RpcDecoderProcessor.
RPC interfaces call generated encoders/decoders.
Redundant mocks were removed.
Proper types are annotated with RpcEncoder/RpcDecoder/ScaleWriter/ScaleReader.
Generated ScaleWriters/ScaleReaders use getters/setters instead of fields.
RpcCallProcessor and RpcSubscriptionProcessor are generalized using parent abstract class.
Scale/ScaleGeneric annotations support parameters and methods(for return value).
ProcessorContext and ProcessingException became common for all generators.
Type(Read/Write)Generator(s) were renamed to (Reader/Writer)Compositor(s).
ScaleReaderNotFoundException and ScaleWriterNotFoundException were removed to support recursive traversing of both types Scale and RPC in parallel and avoid visiting ahead.
Auto registration is not supported more in terms were supposed. All annotated encoders/decoders/writers/readers prefixed the project name (including the company name) are still auto registrable. To auto register external classes
should use the following API, e.g.: `ScaleReaderRegistry.getInstance().registerAnnotatedFrom("com.my-company.my-project")`.
TypeTraverser has started to support primitives. TypeTraverser hasn't been visiting wild card types if generic is Self(Encodable/Writable).
  • Loading branch information
vnabiev committed Oct 26, 2021
1 parent d038a0c commit 12dcc88
Show file tree
Hide file tree
Showing 140 changed files with 3,998 additions and 1,252 deletions.
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.9.12'
implementation 'org.reflections:reflections:0.10.1'
implementation 'com.squareup:javapoet:1.13.0'
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package com.strategyobject.substrateclient.common.codegen;

import com.google.common.base.Preconditions;
import com.squareup.javapoet.AnnotationSpec;
import lombok.NonNull;
import lombok.val;

import javax.lang.model.AnnotatedConstruct;
import javax.lang.model.element.AnnotationMirror;
import java.lang.annotation.Annotation;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public final class AnnotationUtils {
public static AnnotationMirror getAnnotationMirror(@NonNull AnnotatedConstruct target,
@NonNull Class<? extends Annotation> annotationType) {
String annotationTypeName = annotationType.getName();
String annotationTypeName = annotationType.getCanonicalName();
for (val annotationMirror : target.getAnnotationMirrors()) {
if (annotationMirror.getAnnotationType().toString().equals(annotationTypeName)) {
return annotationMirror;
Expand Down Expand Up @@ -41,6 +45,18 @@ public static <T> T getValueFromAnnotation(@NonNull AnnotatedConstruct target,
null;
}

public static AnnotationSpec suppressWarnings(String... warnings) {
Preconditions.checkArgument(warnings != null && warnings.length > 0);
val format = IntStream.range(0, warnings.length)
.boxed()
.map(i -> "$S")
.collect(Collectors.joining(",", "{", "}"));

return AnnotationSpec.builder(SuppressWarnings.class)
.addMember("value", format, (Object[]) warnings)
.build();
}

private AnnotationUtils() {
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.strategyobject.substrateclient.common.codegen;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.WildcardTypeName;
import com.squareup.javapoet.*;
import lombok.NonNull;
import lombok.val;

import javax.lang.model.element.TypeElement;
import java.util.Collections;
import java.util.Map;
import java.util.stream.IntStream;

import static java.util.stream.Collectors.toMap;

public final class JavaPoet {
public static ParameterizedTypeName parameterizeClass(@NonNull TypeElement classElement, TypeName... parameters) {
Expand All @@ -29,6 +30,21 @@ public static TypeName setEachGenericParameterAsWildcard(@NonNull TypeElement cl
return setEachGenericParameterAs(classElement, WildcardTypeName.subtypeOf(Object.class));
}

public static Map<String, Object> args(@NonNull Map<String, Object> map, @NonNull Object... params) {
val target = IntStream.range(0, params.length)
.boxed()
.collect(toMap(i -> String.format("p_%s", i + 1), i -> params[i]));
target.putAll(map);

return target;
}

public static CodeBlock named(@NonNull String format, @NonNull Map<String, Object> aliases) {
return CodeBlock.builder()
.addNamed(format, aliases)
.build();
}

private JavaPoet() {
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.strategyobject.substrateclient.scale.codegen;
package com.strategyobject.substrateclient.common.codegen;

import javax.lang.model.element.Element;

Expand All @@ -14,4 +14,4 @@ public ProcessingException(Throwable cause, Element element, String message, Obj
super(String.format(message, args), cause);
this.element = element;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.strategyobject.substrateclient.common.codegen;

import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;

@RequiredArgsConstructor
@Getter
public class ProcessorContext {
private final @NonNull Types typeUtils;
private final @NonNull Elements elementUtils;
private final @NonNull Filer filer;
private final @NonNull Messager messager;

public String getPackageName(@NonNull TypeElement classElement) {
return elementUtils.getPackageOf(classElement).getQualifiedName().toString();
}

public boolean isSubtypeOf(@NonNull TypeMirror candidate, @NonNull TypeMirror supertype) {
return typeUtils.isAssignable(candidate, supertype);
}

public boolean isGeneric(@NonNull TypeMirror type) {
return ((TypeElement) typeUtils.asElement(type))
.getTypeParameters()
.size() > 0;
}

public TypeMirror erasure(@NonNull TypeMirror type) {
return typeUtils.erasure(type);
}

public TypeMirror getBoxed(@NonNull TypeMirror type) {
return type instanceof PrimitiveType ?
typeUtils.boxedClass((PrimitiveType) type).asType() :
type;
}

public TypeMirror getType(Class<?> clazz) {
return elementUtils.getTypeElement(clazz.getCanonicalName()).asType();
}

public boolean isSameType(@NonNull TypeMirror left, @NonNull TypeMirror right) {
return typeUtils.isSameType(left, right);
}

public void error(Exception exception) {
messager.printMessage(
Diagnostic.Kind.ERROR,
exception.getMessage()
);
}

public void error(Element e, Exception exception) {
messager.printMessage(
Diagnostic.Kind.ERROR,
exception.getMessage(),
e
);
}

public void error(Element e, String message, Object... args) {
messager.printMessage(
Diagnostic.Kind.ERROR,
String.format(message, args),
e
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,13 @@
import lombok.NonNull;
import lombok.val;

import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.*;
import java.lang.reflect.Array;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

public abstract class TypeTraverser<T> {

private final Class<T> clazz;

public TypeTraverser(Class<T> clazz) {
Expand All @@ -23,22 +20,32 @@ public TypeTraverser(Class<T> clazz) {

protected abstract T whenTypeVar(@NonNull TypeVariable type, TypeMirror override);

protected abstract T whenPrimitiveType(@NonNull PrimitiveType type, TypeMirror override);

protected abstract T whenNonGenericType(@NonNull DeclaredType type, TypeMirror override);

protected abstract T whenGenericType(@NonNull DeclaredType type, TypeMirror override, @NonNull T[] subtypes);

protected boolean doTraverseArguments(@NonNull DeclaredType type, TypeMirror override) {
return true;
}

@SuppressWarnings("unchecked")
public T traverse(@NonNull TypeMirror type) {
if (type.getKind() == TypeKind.TYPEVAR) {
return whenTypeVar((TypeVariable) type, null);
}

if (type.getKind().isPrimitive()) {
return whenPrimitiveType((PrimitiveType) type, null);
}

if (!(type instanceof DeclaredType)) {
throw new IllegalArgumentException("Type is not supported: " + type);
}

val declaredType = (DeclaredType) type;
val typeArguments = declaredType.getTypeArguments();
val typeArguments = getTypeArgumentsOrDefault(declaredType, null);
return typeArguments.size() == 0 ?
whenNonGenericType(declaredType, null) :
whenGenericType(
Expand All @@ -55,12 +62,16 @@ public T traverse(@NonNull TypeMirror type, @NonNull TypeTraverser.TypeTreeNode
return whenTypeVar((TypeVariable) type, typeOverride.type);
}

if (type.getKind().isPrimitive()) {
return whenPrimitiveType((PrimitiveType) type, typeOverride.type);
}

if (!(type instanceof DeclaredType)) {
throw new IllegalArgumentException("Type is not supported: " + type);
}

val declaredType = (DeclaredType) type;
val typeArguments = declaredType.getTypeArguments();
val typeArguments = getTypeArgumentsOrDefault(declaredType, typeOverride.type);
val typeArgumentsSize = typeArguments.size();
val typeOverrideSize = typeOverride.children.size();
if (typeIsNonGeneric(typeArgumentsSize, typeOverrideSize)) {
Expand Down Expand Up @@ -90,10 +101,16 @@ public T traverse(@NonNull TypeMirror type, @NonNull TypeTraverser.TypeTreeNode
.toArray(x -> (T[]) Array.newInstance(clazz, typeArguments.size())));
}

private List<? extends TypeMirror> getTypeArgumentsOrDefault(DeclaredType declaredType, TypeMirror override) {
return (doTraverseArguments(declaredType, override) ?
declaredType.getTypeArguments() :
Collections.emptyList());
}

private boolean typeIsNonGeneric(int typeArgumentsSize, int typeOverrideSize) {
if (typeArgumentsSize == 0) {
if (typeOverrideSize > 0) {
throw new IllegalArgumentException("Nongeneric type cannot be overridden by generic");
throw new IllegalArgumentException("Non generic type cannot be overridden by generic");
}

return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.strategyobject.substrateclient.common.codegen;

import lombok.val;

import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeKind;

import static com.strategyobject.substrateclient.common.utils.StringUtils.capitalize;

public class TypeUtils {
private static final String SETTER_PREFIX = "set";
private static final String DEFAULT_GETTER_PREFIX = "get";
private static final String BOOLEAN_GETTER_PREFIX = "is";

public static String getSetterName(String field) {
return SETTER_PREFIX + capitalize(field);
}

public static String getGetterName(VariableElement field) {
val isPrimitiveBoolean = field.asType().getKind() == TypeKind.BOOLEAN;
val fieldName = field.getSimpleName().toString();
if (isPrimitiveBoolean && fieldName.startsWith(BOOLEAN_GETTER_PREFIX)) {
return fieldName;
}

val prefix = isPrimitiveBoolean ?
BOOLEAN_GETTER_PREFIX :
DEFAULT_GETTER_PREFIX;

return prefix + capitalize(fieldName);
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
package com.strategyobject.substrateclient.common.reflection;

import lombok.NonNull;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

public final class Scanner {
private static final Reflections reflections;
private final Reflections reflections;

static {
reflections = new Reflections("", new SubTypesScanner());
private Scanner(String[] prefixes) {
reflections = new Reflections(
new ConfigurationBuilder()
.setUrls(
Arrays.stream(prefixes)
.flatMap(p -> ClasspathHelper.forPackage(p).stream())
.collect(Collectors.toCollection(ArrayList::new)))
);
}

public static <T> Set<Class<? extends T>> getSubTypesOf(Class<T> clazz) {
return reflections.getSubTypesOf(clazz);
public static Scanner forPrefixes(@NonNull String... prefixes){
return new Scanner(prefixes);
}

private Scanner() {
public <T> Set<Class<? extends T>> getSubTypesOf(Class<T> clazz) {
return reflections.getSubTypesOf(clazz);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ public static List<Integer> allIndexesOfAny(@NonNull String target, @NonNull Str
return result;
}

public static String capitalize(@NonNull String source) {
return source.substring(0, 1).toUpperCase() + source.substring(1);
}

private StringUtils() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ class ScannerTest {

@Test
void getSubTypesOf() {
val subtypes = Scanner.getSubTypesOf(TestInterface.class);
val subtypes = Scanner.forPrefixes(TestInterface.class.getPackage().getName())
.getSubTypesOf(TestInterface.class);

assertNotNull(subtypes);
assertEquals(1, subtypes.size());
Expand Down
5 changes: 5 additions & 0 deletions rpc/codegen/build.gradle
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
dependencies {
implementation project(':common')
implementation project(':rpc:core')
implementation project(':scale')
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'

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'

testCompileOnly project(':rpc:codegen')
testAnnotationProcessor project(':rpc:codegen')
testAnnotationProcessor project(':scale:scale-codegen')
}
Loading

0 comments on commit 12dcc88

Please sign in to comment.