Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support of code generation for array types #14

Merged
merged 1 commit into from
May 15, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions api/build.gradle
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
dependencies {
implementation project(':common')
implementation project(':pallet')
implementation project(':rpc')
implementation project(':rpc:rpc-core')
implementation project(':rpc:rpc-sections')
implementation project(':transport')
implementation project(':pallet')
implementation project(':scale')
implementation project(':types')
implementation project(':rpc:rpc-types')
implementation project(':scale')
implementation project(':storage')
implementation project(':transport')
implementation project(':types')

testImplementation project(':tests')

testImplementation 'org.testcontainers:testcontainers:1.16.3'
testImplementation 'org.testcontainers:junit-jupiter:1.16.3'
testImplementation 'org.testcontainers:testcontainers:1.17.1'
testImplementation 'org.testcontainers:junit-jupiter:1.17.1'

testAnnotationProcessor project(':pallet:pallet-codegen')
}
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -26,8 +26,8 @@ subprojects {
implementation 'com.google.guava:guava:30.1.1-jre'
implementation 'org.slf4j:slf4j-api:1.7.32'

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.2'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.2'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.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'
2 changes: 2 additions & 0 deletions common/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
dependencies {
implementation 'org.reflections:reflections:0.10.2'
implementation 'com.squareup:javapoet:1.13.0'

testImplementation project(':tests')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.strategyobject.substrateclient.common;

public interface CommonType {
class Array<T> implements CommonType {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.strategyobject.substrateclient.common.codegen;

import com.strategyobject.substrateclient.common.CommonType;

public class Constants {
public static final Class<?> ARRAY_TYPE = CommonType.Array.class;

private Constants() {
}
}
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
import javax.annotation.processing.Messager;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
@@ -33,11 +34,16 @@ public boolean isAssignable(@NonNull TypeMirror candidate, @NonNull TypeMirror s
public boolean isSubtype(@NonNull TypeMirror candidate, @NonNull TypeMirror supertype) {
return typeUtils.isSubtype(candidate, supertype);
}

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

public boolean isNonGeneric(@NonNull TypeMirror type) {
if (type instanceof ArrayType) {
return isNonGeneric(((ArrayType) type).getComponentType());
}

return type.getKind().isPrimitive() ||
((TypeElement) typeUtils.asElement(type))
.getTypeParameters()
.size() == 0;
}

public TypeMirror erasure(@NonNull TypeMirror type) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.strategyobject.substrateclient.common.codegen;

import javax.lang.model.type.TypeMirror;

public class TypeNotSupportedException extends IllegalArgumentException {
public TypeNotSupportedException(TypeMirror type) {
super("Type is not supported: " + type);
}
}
Original file line number Diff line number Diff line change
@@ -26,6 +26,10 @@ public TypeTraverser(Class<T> clazz) {

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

protected abstract T whenArrayPrimitiveType(@NonNull ArrayType type, TypeMirror override);

protected abstract T whenArrayType(@NonNull ArrayType type, TypeMirror override, @NonNull T subtype);

protected boolean doTraverseArguments(@NonNull DeclaredType type, TypeMirror override) {
return true;
}
@@ -40,20 +44,32 @@ public T traverse(@NonNull TypeMirror type) {
return whenPrimitiveType((PrimitiveType) type, null);
}

if (type instanceof ArrayType) {
val arrayType = (ArrayType) type;
return arrayType.getComponentType().getKind().isPrimitive() ?
whenArrayPrimitiveType(arrayType, null) :
whenArrayType(
arrayType,
null,
traverse(arrayType.getComponentType()));
}

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

val declaredType = (DeclaredType) type;
val typeArguments = getTypeArgumentsOrDefault(declaredType, null);
return typeArguments.size() == 0 ?
whenNonGenericType(declaredType, null) :
whenGenericType(
declaredType,
null,
typeArguments.stream()
.map(this::traverse)
.toArray(x -> (T[]) Array.newInstance(clazz, typeArguments.size())));
if (typeArguments.size() == 0) {
return whenNonGenericType(declaredType, null);
}

return whenGenericType(
declaredType,
null,
typeArguments.stream()
.map(this::traverse)
.toArray(x -> (T[]) Array.newInstance(clazz, typeArguments.size())));
}

@SuppressWarnings({"unchecked", "UnstableApiUsage"})
@@ -66,8 +82,30 @@ public T traverse(@NonNull TypeMirror type, @NonNull TypeTraverser.TypeTreeNode
return whenPrimitiveType((PrimitiveType) type, typeOverride.type);
}

if (type instanceof ArrayType) {
val arrayType = (ArrayType) type;
if (arrayType.getComponentType().getKind().isPrimitive()) {
return whenArrayPrimitiveType(arrayType, typeOverride.type);
}

switch (typeOverride.children.size()) {
case 0:
return whenArrayType(
arrayType,
typeOverride.type,
traverse(arrayType.getComponentType()));
case 1:
return whenArrayType(
arrayType,
typeOverride.type,
traverse(arrayType.getComponentType(), typeOverride.children.get(0)));
default:
throw new IllegalArgumentException("Array type cannot be overridden by a generic type with more than one parameter");
}
}

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

val declaredType = (DeclaredType) type;
@@ -107,8 +145,18 @@ public T traverse(@NonNull TypeTraverser.TypeTreeNode typeOverride) {
return whenPrimitiveType((PrimitiveType) typeOverride.type, typeOverride.type);
}

if (typeOverride.type instanceof ArrayType) {
val arrayType = (ArrayType) typeOverride.type;
return arrayType.getComponentType().getKind().isPrimitive() ?
whenArrayPrimitiveType(arrayType, arrayType) :
whenArrayType(
arrayType,
arrayType,
traverse(arrayType.getComponentType()));
}

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

val declaredType = (DeclaredType) typeOverride.type;
Original file line number Diff line number Diff line change
@@ -3,7 +3,10 @@
import lombok.val;

import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;

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

@@ -29,4 +32,20 @@ public static String getGetterName(VariableElement field) {

return prefix + capitalize(fieldName);
}

public static String getSimpleName(TypeMirror type) {
if (type.getKind().isPrimitive()) {
return type.toString();
}

if (type instanceof DeclaredType) {
return ((DeclaredType) type).asElement().getSimpleName().toString();
}

if (type instanceof ArrayType) {
return String.format("%s[]", getSimpleName(((ArrayType) type).getComponentType()));
}

throw new IllegalArgumentException(String.format("Cannot populate the name of %s", type));
}
}
Loading