diff --git a/api/build.gradle b/api/build.gradle index 30e9f7b2..44dc6ea0 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -7,15 +7,17 @@ dependencies { implementation project(':scale') implementation project(':transport') + implementation 'com.google.inject:guice:5.1.0' + annotationProcessor project(':pallet:pallet-codegen') annotationProcessor project(':rpc:rpc-codegen') testImplementation project(':tests') - testAnnotationProcessor project(':pallet:pallet-codegen') - testImplementation 'ch.qos.logback:logback-classic:1.2.11' - testImplementation 'org.testcontainers:testcontainers:1.17.1' - testImplementation 'org.testcontainers:junit-jupiter:1.17.1' + testImplementation 'org.testcontainers:testcontainers:1.17.2' + testImplementation 'org.testcontainers:junit-jupiter:1.17.2' testImplementation 'org.awaitility:awaitility:4.2.0' -} \ No newline at end of file + + testAnnotationProcessor project(':pallet:pallet-codegen') +} diff --git a/api/src/main/java/com/strategyobject/substrateclient/api/Api.java b/api/src/main/java/com/strategyobject/substrateclient/api/Api.java index bc064268..8516008d 100644 --- a/api/src/main/java/com/strategyobject/substrateclient/api/Api.java +++ b/api/src/main/java/com/strategyobject/substrateclient/api/Api.java @@ -1,32 +1,27 @@ package com.strategyobject.substrateclient.api; -import com.strategyobject.substrateclient.pallet.GeneratedPalletResolver; -import com.strategyobject.substrateclient.pallet.PalletResolver; -import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; -import com.strategyobject.substrateclient.rpc.api.section.State; +import com.google.inject.Module; +import com.strategyobject.substrateclient.pallet.PalletFactory; +import com.strategyobject.substrateclient.rpc.RpcSectionFactory; import com.strategyobject.substrateclient.transport.ProviderInterface; import lombok.NonNull; -import lombok.val; +import lombok.RequiredArgsConstructor; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; /** * Provides the ability to query a node and interact with the Polkadot or Substrate chains. * It allows interacting with blockchain in various ways: using RPC's queries directly or * accessing Pallets and its APIs, such as storages, transactions, etc. */ +@RequiredArgsConstructor public class Api implements AutoCloseable { - private final @NonNull ProviderInterface providerInterface; - private final @NonNull PalletResolver palletResolver; + private final @NonNull RpcSectionFactory rpcSectionFactory; + private final @NonNull PalletFactory palletFactory; private final Map, Object> resolvedCache = new ConcurrentHashMap<>(); - private Api(@NonNull ProviderInterface providerInterface) { - this.providerInterface = providerInterface; - - val state = RpcGeneratedSectionFactory.create(State.class, providerInterface); - this.palletResolver = GeneratedPalletResolver.with(state); - } /** * Resolves the instance of a rpc by its definition. @@ -35,9 +30,8 @@ private Api(@NonNull ProviderInterface providerInterface) { * @param the type of the rpc * @return appropriate instance of the rpc */ - public T rpc(Class clazz) { - return clazz.cast(resolvedCache - .computeIfAbsent(clazz, x -> RpcGeneratedSectionFactory.create(x, providerInterface))); + public T rpc(@NonNull Class clazz) { + return clazz.cast(resolvedCache.computeIfAbsent(clazz, rpcSectionFactory::create)); } /** @@ -48,18 +42,21 @@ public T rpc(Class clazz) { * @return appropriate instance of the pallet */ public T pallet(@NonNull Class clazz) { - return clazz.cast(resolvedCache - .computeIfAbsent(clazz, palletResolver::resolve)); - } - - public static Api with(ProviderInterface providerInterface) { - return new Api(providerInterface); + return clazz.cast(resolvedCache.computeIfAbsent(clazz, palletFactory::create)); } @Override public void close() throws Exception { - if (providerInterface instanceof AutoCloseable) { - ((AutoCloseable) providerInterface).close(); + if (rpcSectionFactory instanceof AutoCloseable) { + ((AutoCloseable) rpcSectionFactory).close(); } } + + public static ApiBuilder with(@NonNull Supplier providerInterface) { + return with(new DefaultModule(providerInterface.get())); + } + + public static ApiBuilder with(@NonNull M module) { + return new ApiBuilder<>(module); + } } \ No newline at end of file diff --git a/api/src/main/java/com/strategyobject/substrateclient/api/ApiBuilder.java b/api/src/main/java/com/strategyobject/substrateclient/api/ApiBuilder.java new file mode 100644 index 00000000..d86e9b2d --- /dev/null +++ b/api/src/main/java/com/strategyobject/substrateclient/api/ApiBuilder.java @@ -0,0 +1,36 @@ +package com.strategyobject.substrateclient.api; + +import com.google.inject.Guice; +import com.google.inject.Module; +import com.strategyobject.substrateclient.transport.ProviderInterface; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.val; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Function; + +@RequiredArgsConstructor +public class ApiBuilder { + private final @NonNull M module; + + public ApiBuilder configure(@NonNull Consumer configuration) { + configuration.accept(module); + return this; + } + + public ApiBuilder reconfigure(@NonNull Function configuration) { + return new ApiBuilder<>(configuration.apply(this.module)); + } + + public CompletableFuture build() { + val injector = Guice.createInjector(new RequireModule(), module); + val provider = injector.getInstance(ProviderInterface.class); + val result = provider.isConnected() ? + CompletableFuture.completedFuture(null) : + provider.connect(); + + return result.thenApply(ignored -> injector.getInstance(Api.class)); + } +} diff --git a/api/src/main/java/com/strategyobject/substrateclient/api/DefaultModule.java b/api/src/main/java/com/strategyobject/substrateclient/api/DefaultModule.java new file mode 100644 index 00000000..4441f96d --- /dev/null +++ b/api/src/main/java/com/strategyobject/substrateclient/api/DefaultModule.java @@ -0,0 +1,125 @@ +package com.strategyobject.substrateclient.api; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.strategyobject.substrateclient.common.types.AutoRegistry; +import com.strategyobject.substrateclient.pallet.GeneratedPalletFactory; +import com.strategyobject.substrateclient.pallet.PalletFactory; +import com.strategyobject.substrateclient.rpc.GeneratedRpcSectionFactory; +import com.strategyobject.substrateclient.rpc.RpcSectionFactory; +import com.strategyobject.substrateclient.rpc.api.section.State; +import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry; +import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import com.strategyobject.substrateclient.transport.ProviderInterface; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.val; + +import java.util.function.Consumer; + +@RequiredArgsConstructor +public class DefaultModule extends AbstractModule { + private final @NonNull ProviderInterface providerInterface; + + private Consumer configureScaleReaderRegistry = this::autoRegister; + private Consumer configureScaleWriterRegistry = this::autoRegister; + private Consumer configureRpcDecoderRegistry = this::autoRegister; + private Consumer configureRpcEncoderRegistry = this::autoRegister; + + private void autoRegister(AutoRegistry registry) { + registry.registerAnnotatedFrom("com.strategyobject.substrateclient"); + } + + public DefaultModule configureScaleReaderRegistry(Consumer configure) { + configureScaleReaderRegistry = configureScaleReaderRegistry.andThen(configure); + return this; + } + + public DefaultModule configureScaleWriterRegistry(Consumer configure) { + configureScaleWriterRegistry = configureScaleWriterRegistry.andThen(configure); + return this; + } + + public DefaultModule configureRpcDecoderRegistry(Consumer configure) { + configureRpcDecoderRegistry = configureRpcDecoderRegistry.andThen(configure); + return this; + } + + public DefaultModule configureRpcEncoderRegistry(Consumer configure) { + configureRpcEncoderRegistry = configureRpcEncoderRegistry.andThen(configure); + return this; + } + + @Override + protected void configure() { + try { + bind(ProviderInterface.class).toInstance(providerInterface); + bind(RpcSectionFactory.class) + .toConstructor( + GeneratedRpcSectionFactory.class.getConstructor( + ProviderInterface.class, + RpcEncoderRegistry.class, + ScaleWriterRegistry.class, + RpcDecoderRegistry.class, + ScaleReaderRegistry.class)) + .asEagerSingleton(); + bind(PalletFactory.class) + .toConstructor( + GeneratedPalletFactory.class.getConstructor( + ScaleReaderRegistry.class, + ScaleWriterRegistry.class, + State.class + )) + .asEagerSingleton(); + bind(Api.class) + .toConstructor( + Api.class.getConstructor( + RpcSectionFactory.class, + PalletFactory.class)) + .asEagerSingleton(); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + @Provides + @Singleton + public ScaleReaderRegistry provideScaleReaderRegistry() { + val registry = new ScaleReaderRegistry(); + configureScaleReaderRegistry.accept(registry); + return registry; + } + + @Provides + @Singleton + public ScaleWriterRegistry provideScaleWriterRegistry() { + val registry = new ScaleWriterRegistry(); + configureScaleWriterRegistry.accept(registry); + return registry; + } + + @Provides + @Singleton + public RpcDecoderRegistry provideRpcDecoderRegistry(ScaleReaderRegistry scaleReaderRegistry) { + val registry = new RpcDecoderRegistry(scaleReaderRegistry); + configureRpcDecoderRegistry.accept(registry); + return registry; + } + + @Provides + @Singleton + public RpcEncoderRegistry provideRpcEncoderRegistry(ScaleWriterRegistry scaleWriterRegistry) { + val registry = new RpcEncoderRegistry(scaleWriterRegistry); + configureRpcEncoderRegistry.accept(registry); + return registry; + } + + @Provides + @Singleton + public State provideState(RpcSectionFactory rpcSectionFactory) { + return rpcSectionFactory.create(State.class); + } +} diff --git a/api/src/main/java/com/strategyobject/substrateclient/api/RequireModule.java b/api/src/main/java/com/strategyobject/substrateclient/api/RequireModule.java new file mode 100644 index 00000000..955429e9 --- /dev/null +++ b/api/src/main/java/com/strategyobject/substrateclient/api/RequireModule.java @@ -0,0 +1,24 @@ +package com.strategyobject.substrateclient.api; + +import com.google.inject.AbstractModule; +import com.strategyobject.substrateclient.pallet.PalletFactory; +import com.strategyobject.substrateclient.rpc.RpcSectionFactory; +import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry; +import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import com.strategyobject.substrateclient.transport.ProviderInterface; + +public class RequireModule extends AbstractModule { + @Override + protected void configure() { + requireBinding(ProviderInterface.class); + requireBinding(ScaleReaderRegistry.class); + requireBinding(ScaleWriterRegistry.class); + requireBinding(RpcDecoderRegistry.class); + requireBinding(RpcEncoderRegistry.class); + requireBinding(RpcSectionFactory.class); + requireBinding(PalletFactory.class); + requireBinding(Api.class); + } +} diff --git a/api/src/test/java/com/strategyobject/substrateclient/api/ApiTests.java b/api/src/test/java/com/strategyobject/substrateclient/api/ApiTests.java index ace57ff1..85ab6973 100644 --- a/api/src/test/java/com/strategyobject/substrateclient/api/ApiTests.java +++ b/api/src/test/java/com/strategyobject/substrateclient/api/ApiTests.java @@ -1,6 +1,13 @@ package com.strategyobject.substrateclient.api; +import com.google.inject.CreationException; +import com.google.inject.util.Modules; +import com.strategyobject.substrateclient.common.convert.HexConverter; +import com.strategyobject.substrateclient.pallet.PalletFactory; +import com.strategyobject.substrateclient.rpc.api.AccountId; import com.strategyobject.substrateclient.rpc.api.BlockNumber; +import com.strategyobject.substrateclient.rpc.api.Index; +import com.strategyobject.substrateclient.rpc.api.section.System; import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; import com.strategyobject.substrateclient.tests.containers.TestSubstrateContainer; import com.strategyobject.substrateclient.transport.ws.WsProvider; @@ -12,8 +19,9 @@ import java.math.BigInteger; import java.util.concurrent.TimeUnit; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; @Testcontainers class ApiTests { @@ -25,11 +33,9 @@ class ApiTests { @Test void getSystemPalletAndCall() throws Exception { // TODO move the test out of the project val wsProvider = WsProvider.builder() - .setEndpoint(substrate.getWsAddress()) - .build(); - wsProvider.connect().get(WAIT_TIMEOUT, TimeUnit.SECONDS); + .setEndpoint(substrate.getWsAddress()); - try (val api = Api.with(wsProvider)) { + try (val api = Api.with(wsProvider).build().join()) { val systemPallet = api.pallet(SystemPallet.class); val blockHash = systemPallet .blockHash() @@ -37,7 +43,69 @@ void getSystemPalletAndCall() throws Exception { // TODO move the test out of th .get(WAIT_TIMEOUT, TimeUnit.SECONDS); assertNotNull(blockHash); - assertNotEquals(BigInteger.ZERO, new BigInteger(blockHash.getData())); + assertNotEquals(BigInteger.ZERO, new BigInteger(blockHash.getBytes())); } } + + @Test + void getSystemSectionAndCall() throws Exception { + val wsProvider = WsProvider.builder() + .setEndpoint(substrate.getWsAddress()); + + try (val api = Api.with(wsProvider).build().join()) { + val system = api.rpc(System.class); + val alicePublicKey = HexConverter.toBytes("0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"); + val actual = system.accountNextIndex(AccountId.fromBytes(alicePublicKey)).join(); + + assertEquals(Index.ZERO, actual); + } + } + + @Test + void configureApi() throws Exception { + val wsProvider = WsProvider.builder() + .setEndpoint(substrate.getWsAddress()); + + val expected = mock(Index.class); + try (val api = Api.with(wsProvider) + .configure(defaultModule -> + defaultModule.configureRpcDecoderRegistry(registry -> + registry.register( + (value, decoders) -> expected, + Index.class))) + .build() + .join()) { + val system = api.rpc(System.class); + val alicePublicKey = HexConverter.toBytes("0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"); + val actual = system.accountNextIndex(AccountId.fromBytes(alicePublicKey)).join(); + + assertEquals(expected, actual); + } + } + + @Test + void reconfigureApi() throws Exception { + val wsProvider = WsProvider.builder() + .setEndpoint(substrate.getWsAddress()); + + val mockFactory = mock(PalletFactory.class); + try (val api = Api.with(wsProvider) + .reconfigure(defaultModule -> + Modules.override(defaultModule).with(binder -> + binder.bind(PalletFactory.class).toInstance(mockFactory))) + .build() + .join()) { + + api.pallet(SystemPallet.class); + verify(mockFactory).create(SystemPallet.class); + } + } + + @Test + void validateModule() { + val api = Api.with(binder -> { + }); + + assertThrows(CreationException.class, api::build); + } } diff --git a/api/src/test/java/com/strategyobject/substrateclient/api/SystemPallet.java b/api/src/test/java/com/strategyobject/substrateclient/api/SystemPallet.java index 9b23591d..8c53eaa7 100644 --- a/api/src/test/java/com/strategyobject/substrateclient/api/SystemPallet.java +++ b/api/src/test/java/com/strategyobject/substrateclient/api/SystemPallet.java @@ -12,7 +12,7 @@ @Pallet("System") public interface SystemPallet { @Storage( - value = "BlockHash", + name = "BlockHash", keys = { @StorageKey( type = @Scale(BlockNumber.class), diff --git a/build.gradle b/build.gradle index a53b1cbf..e8804dd4 100644 --- a/build.gradle +++ b/build.gradle @@ -23,17 +23,17 @@ subprojects { sourceCompatibility = '1.8' dependencies { - implementation 'com.google.guava:guava:30.1.1-jre' - implementation 'org.slf4j:slf4j-api:1.7.32' + implementation 'com.google.guava:guava:31.1-jre' + implementation 'org.slf4j:slf4j-api:1.7.36' 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' - testImplementation 'org.slf4j:slf4j-simple:1.7.32' + testImplementation 'org.assertj:assertj-core:3.23.1' + testImplementation 'org.mockito:mockito-core:4.6.1' + testImplementation 'org.mockito:mockito-inline:4.6.1' + testImplementation 'org.slf4j:slf4j-simple:1.7.36' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' } test { diff --git a/common/src/main/java/com/strategyobject/substrateclient/common/codegen/AnnotationUtils.java b/common/src/main/java/com/strategyobject/substrateclient/common/codegen/AnnotationUtils.java index 735dd9d9..bf9e5b08 100644 --- a/common/src/main/java/com/strategyobject/substrateclient/common/codegen/AnnotationUtils.java +++ b/common/src/main/java/com/strategyobject/substrateclient/common/codegen/AnnotationUtils.java @@ -8,6 +8,7 @@ import javax.lang.model.AnnotatedConstruct; import javax.lang.model.element.AnnotationMirror; import java.lang.annotation.Annotation; +import java.util.Arrays; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -57,6 +58,20 @@ public static AnnotationSpec suppressWarnings(String... warnings) { .build(); } + public static boolean isAnnotatedWith(AnnotatedConstruct annotated, Class annotation) { + return annotated.getAnnotation(annotation) != null; + } + + @SafeVarargs + public static boolean isAnnotatedWithAny(AnnotatedConstruct annotated, Class... annotations) { + return Arrays.stream(annotations).anyMatch(x -> annotated.getAnnotation(x) != null); + } + + @SafeVarargs + public static boolean isAnnotatedWithAll(AnnotatedConstruct annotated, Class... annotations) { + return Arrays.stream(annotations).allMatch(x -> annotated.getAnnotation(x) != null); + } + private AnnotationUtils() { } } diff --git a/common/src/main/java/com/strategyobject/substrateclient/common/codegen/TypeNotSupportedException.java b/common/src/main/java/com/strategyobject/substrateclient/common/codegen/TypeNotSupportedException.java index 58f5561f..afa10579 100644 --- a/common/src/main/java/com/strategyobject/substrateclient/common/codegen/TypeNotSupportedException.java +++ b/common/src/main/java/com/strategyobject/substrateclient/common/codegen/TypeNotSupportedException.java @@ -3,7 +3,11 @@ import javax.lang.model.type.TypeMirror; public class TypeNotSupportedException extends IllegalArgumentException { - public TypeNotSupportedException(TypeMirror type) { + public TypeNotSupportedException(String type) { super("Type is not supported: " + type); } + + public TypeNotSupportedException(TypeMirror type) { + this(type.toString()); + } } diff --git a/common/src/main/java/com/strategyobject/substrateclient/common/codegen/TypeTraverser.java b/common/src/main/java/com/strategyobject/substrateclient/common/codegen/TypeTraverser.java index 67b48136..56db007c 100644 --- a/common/src/main/java/com/strategyobject/substrateclient/common/codegen/TypeTraverser.java +++ b/common/src/main/java/com/strategyobject/substrateclient/common/codegen/TypeTraverser.java @@ -7,17 +7,18 @@ 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 { private final Class clazz; - public TypeTraverser(Class clazz) { + protected TypeTraverser(Class clazz) { this.clazz = clazz; } + protected abstract T whenWildcard(TypeMirror override); + protected abstract T whenTypeVar(@NonNull TypeVariable type, TypeMirror override); protected abstract T whenPrimitiveType(@NonNull PrimitiveType type, TypeMirror override); @@ -30,12 +31,12 @@ public TypeTraverser(Class clazz) { protected abstract T whenArrayType(@NonNull ArrayType type, TypeMirror override, @NonNull T subtype); - protected boolean doTraverseArguments(@NonNull DeclaredType type, TypeMirror override) { - return true; - } - @SuppressWarnings("unchecked") public T traverse(@NonNull TypeMirror type) { + if (type.getKind() == TypeKind.WILDCARD) { + return whenWildcard(null); + } + if (type.getKind() == TypeKind.TYPEVAR) { return whenTypeVar((TypeVariable) type, null); } @@ -57,9 +58,8 @@ public T traverse(@NonNull TypeMirror type) { if (!(type instanceof DeclaredType)) { throw new TypeNotSupportedException(type); } - val declaredType = (DeclaredType) type; - val typeArguments = getTypeArgumentsOrDefault(declaredType, null); + val typeArguments = getTypeArguments(declaredType, null); if (typeArguments.size() == 0) { return whenNonGenericType(declaredType, null); } @@ -74,6 +74,10 @@ public T traverse(@NonNull TypeMirror type) { @SuppressWarnings({"unchecked", "UnstableApiUsage"}) public T traverse(@NonNull TypeMirror type, @NonNull TypeTraverser.TypeTreeNode typeOverride) { + if (type.getKind() == TypeKind.WILDCARD) { + return whenWildcard(typeOverride.type); + } + if (type.getKind() == TypeKind.TYPEVAR) { return whenTypeVar((TypeVariable) type, typeOverride.type); } @@ -109,7 +113,7 @@ public T traverse(@NonNull TypeMirror type, @NonNull TypeTraverser.TypeTreeNode } val declaredType = (DeclaredType) type; - val typeArguments = getTypeArgumentsOrDefault(declaredType, typeOverride.type); + val typeArguments = getTypeArguments(declaredType, typeOverride.type); val typeArgumentsSize = typeArguments.size(); val typeOverrideSize = typeOverride.children.size(); if (typeIsNonGeneric(typeArgumentsSize, typeOverrideSize)) { @@ -117,12 +121,17 @@ public T traverse(@NonNull TypeMirror type, @NonNull TypeTraverser.TypeTreeNode } if (typeIsOverriddenByNonGeneric(typeOverrideSize)) { + if (typeOverride.type != null) { + return whenGenericType(declaredType, typeOverride.type, (T[]) Array.newInstance(clazz, 0)); + } + return whenGenericType( declaredType, - typeOverride.type, + null, typeArguments.stream() .map(this::traverse) .toArray(x -> (T[]) Array.newInstance(clazz, typeArguments.size()))); + } if (typeOverrideSize != typeArgumentsSize) { @@ -172,10 +181,8 @@ public T traverse(@NonNull TypeTraverser.TypeTreeNode typeOverride) { .toArray(x -> (T[]) Array.newInstance(clazz, typeOverride.children.size()))); } - private List getTypeArgumentsOrDefault(DeclaredType declaredType, TypeMirror override) { - return (doTraverseArguments(declaredType, override) ? - declaredType.getTypeArguments() : - Collections.emptyList()); + protected List getTypeArguments(DeclaredType declaredType, TypeMirror override) { + return declaredType.getTypeArguments(); } private boolean typeIsNonGeneric(int typeArgumentsSize, int typeOverrideSize) { diff --git a/common/src/main/java/com/strategyobject/substrateclient/common/codegen/TypeUtils.java b/common/src/main/java/com/strategyobject/substrateclient/common/codegen/TypeUtils.java index 9bb24b01..98ca9c46 100644 --- a/common/src/main/java/com/strategyobject/substrateclient/common/codegen/TypeUtils.java +++ b/common/src/main/java/com/strategyobject/substrateclient/common/codegen/TypeUtils.java @@ -8,7 +8,7 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -import static com.strategyobject.substrateclient.common.utils.StringUtils.capitalize; +import static com.strategyobject.substrateclient.common.strings.StringUtils.capitalize; public class TypeUtils { private static final String SETTER_PREFIX = "set"; diff --git a/common/src/main/java/com/strategyobject/substrateclient/common/utils/HexConverter.java b/common/src/main/java/com/strategyobject/substrateclient/common/convert/HexConverter.java similarity index 93% rename from common/src/main/java/com/strategyobject/substrateclient/common/utils/HexConverter.java rename to common/src/main/java/com/strategyobject/substrateclient/common/convert/HexConverter.java index 7136b08f..bc511fe0 100644 --- a/common/src/main/java/com/strategyobject/substrateclient/common/utils/HexConverter.java +++ b/common/src/main/java/com/strategyobject/substrateclient/common/convert/HexConverter.java @@ -1,4 +1,4 @@ -package com.strategyobject.substrateclient.common.utils; +package com.strategyobject.substrateclient.common.convert; import com.google.common.base.Preconditions; import lombok.NonNull; @@ -9,7 +9,9 @@ public class HexConverter { private static final char[] HEX = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; public static String toHex(byte @NonNull [] data) { - Preconditions.checkArgument(data.length > 0); + if (data.length == 0) { + return "0x"; + } val hex = new char[(data.length * 2) + 2]; hex[0] = '0'; diff --git a/common/src/main/java/com/strategyobject/substrateclient/common/reflection/ClassUtils.java b/common/src/main/java/com/strategyobject/substrateclient/common/reflection/ClassUtils.java new file mode 100644 index 00000000..3ce1166a --- /dev/null +++ b/common/src/main/java/com/strategyobject/substrateclient/common/reflection/ClassUtils.java @@ -0,0 +1,19 @@ +package com.strategyobject.substrateclient.common.reflection; + +import lombok.val; + +public final class ClassUtils { + + public static boolean hasDefaultConstructor(Class clazz) { + for (val constructor : clazz.getConstructors()) { + if (constructor.getParameterCount() == 0) { + return true; + } + } + + return false; + } + + private ClassUtils() { + } +} diff --git a/common/src/main/java/com/strategyobject/substrateclient/common/utils/StringUtils.java b/common/src/main/java/com/strategyobject/substrateclient/common/strings/StringUtils.java similarity index 95% rename from common/src/main/java/com/strategyobject/substrateclient/common/utils/StringUtils.java rename to common/src/main/java/com/strategyobject/substrateclient/common/strings/StringUtils.java index 4673604f..35749e5a 100644 --- a/common/src/main/java/com/strategyobject/substrateclient/common/utils/StringUtils.java +++ b/common/src/main/java/com/strategyobject/substrateclient/common/strings/StringUtils.java @@ -1,4 +1,4 @@ -package com.strategyobject.substrateclient.common.utils; +package com.strategyobject.substrateclient.common.strings; import com.google.common.base.Preconditions; import lombok.NonNull; diff --git a/common/src/main/java/com/strategyobject/substrateclient/common/types/AutoRegistry.java b/common/src/main/java/com/strategyobject/substrateclient/common/types/AutoRegistry.java new file mode 100644 index 00000000..10afd8d1 --- /dev/null +++ b/common/src/main/java/com/strategyobject/substrateclient/common/types/AutoRegistry.java @@ -0,0 +1,5 @@ +package com.strategyobject.substrateclient.common.types; + +public interface AutoRegistry { + void registerAnnotatedFrom(String... prefixes); +} diff --git a/common/src/main/java/com/strategyobject/substrateclient/common/types/Bytes.java b/common/src/main/java/com/strategyobject/substrateclient/common/types/Bytes.java index 26922321..52347492 100644 --- a/common/src/main/java/com/strategyobject/substrateclient/common/types/Bytes.java +++ b/common/src/main/java/com/strategyobject/substrateclient/common/types/Bytes.java @@ -1,6 +1,8 @@ package com.strategyobject.substrateclient.common.types; +import lombok.NonNull; + @FunctionalInterface public interface Bytes { - byte[] getData(); + byte @NonNull [] getBytes(); } diff --git a/common/src/main/java/com/strategyobject/substrateclient/common/types/FixedBytes.java b/common/src/main/java/com/strategyobject/substrateclient/common/types/FixedBytes.java index ce044169..8dd39bf9 100644 --- a/common/src/main/java/com/strategyobject/substrateclient/common/types/FixedBytes.java +++ b/common/src/main/java/com/strategyobject/substrateclient/common/types/FixedBytes.java @@ -2,21 +2,25 @@ import com.google.common.base.Preconditions; import lombok.EqualsAndHashCode; -import lombok.Getter; +import lombok.NonNull; @EqualsAndHashCode public abstract class FixedBytes implements Fixed, Bytes { - @Getter - private final byte[] data; + private final byte @NonNull [] bytes; - protected FixedBytes(byte[] data, S size) { - Preconditions.checkNotNull(data); - assertSize(size, data.length); + @Override + public byte @NonNull [] getBytes() { + return bytes; + } + + protected FixedBytes(byte @NonNull [] bytes, S size) { + Preconditions.checkNotNull(bytes); + assertSize(size, bytes.length); - this.data = data; + this.bytes = bytes; } public int getSize() { - return data.length; + return bytes.length; } } diff --git a/common/src/test/java/com/strategyobject/substrateclient/common/utils/HexConverterTests.java b/common/src/test/java/com/strategyobject/substrateclient/common/convert/HexConverterTests.java similarity index 96% rename from common/src/test/java/com/strategyobject/substrateclient/common/utils/HexConverterTests.java rename to common/src/test/java/com/strategyobject/substrateclient/common/convert/HexConverterTests.java index 0d7934a9..bb95bd60 100644 --- a/common/src/test/java/com/strategyobject/substrateclient/common/utils/HexConverterTests.java +++ b/common/src/test/java/com/strategyobject/substrateclient/common/convert/HexConverterTests.java @@ -1,4 +1,4 @@ -package com.strategyobject.substrateclient.common.utils; +package com.strategyobject.substrateclient.common.convert; import com.strategyobject.substrateclient.tests.TestSuite; import lombok.AccessLevel; @@ -21,15 +21,15 @@ Stream toHex() { Test.toHex(new byte[]{(byte) 255, 0}, "0xff00"), Test.toHex(new byte[]{(byte) 0, (byte) 255}, "0x00ff"), Test.toHex(new byte[]{127, (byte) 128}, "0x7f80"), - Test.toHex(new byte[]{(byte) 128, (byte) 127}, "0x807f") + Test.toHex(new byte[]{(byte) 128, (byte) 127}, "0x807f"), + Test.toHex(new byte[0], "0x") ); } @TestFactory Stream toHexThrows() { return TestSuite.of( - Test.toHex(null, IllegalArgumentException.class), - Test.toHex(new byte[]{}, IllegalArgumentException.class) + Test.toHex(null, IllegalArgumentException.class) ); } diff --git a/common/src/test/java/com/strategyobject/substrateclient/common/utils/StringUtilsTest.java b/common/src/test/java/com/strategyobject/substrateclient/common/strings/StringUtilsTest.java similarity index 94% rename from common/src/test/java/com/strategyobject/substrateclient/common/utils/StringUtilsTest.java rename to common/src/test/java/com/strategyobject/substrateclient/common/strings/StringUtilsTest.java index f6c9d6f2..4db4208a 100644 --- a/common/src/test/java/com/strategyobject/substrateclient/common/utils/StringUtilsTest.java +++ b/common/src/test/java/com/strategyobject/substrateclient/common/strings/StringUtilsTest.java @@ -1,4 +1,4 @@ -package com.strategyobject.substrateclient.common.utils; +package com.strategyobject.substrateclient.common.strings; import lombok.val; import org.junit.jupiter.api.Test; diff --git a/crypto/src/main/java/com/strategyobject/substrateclient/crypto/CryptoProvider.java b/crypto/src/main/java/com/strategyobject/substrateclient/crypto/CryptoProvider.java index 610e1812..4f985583 100644 --- a/crypto/src/main/java/com/strategyobject/substrateclient/crypto/CryptoProvider.java +++ b/crypto/src/main/java/com/strategyobject/substrateclient/crypto/CryptoProvider.java @@ -1,11 +1,12 @@ package com.strategyobject.substrateclient.crypto; +import com.strategyobject.substrateclient.common.types.Bytes; import lombok.NonNull; public interface CryptoProvider { KeyPair createPairFromSeed(@NonNull Seed seed); - SignatureData sign(@NonNull PublicKey publicKey, @NonNull SecretKey secretKey, @NonNull Signable message); + SignatureData sign(@NonNull PublicKey publicKey, @NonNull SecretKey secretKey, @NonNull Bytes message); - boolean verify(@NonNull SignatureData signature, @NonNull Signable message, @NonNull PublicKey publicKey); + boolean verify(@NonNull SignatureData signature, @NonNull Bytes message, @NonNull PublicKey publicKey); } diff --git a/crypto/src/main/java/com/strategyobject/substrateclient/crypto/KeyPair.java b/crypto/src/main/java/com/strategyobject/substrateclient/crypto/KeyPair.java index 2bdff344..47bdf50f 100644 --- a/crypto/src/main/java/com/strategyobject/substrateclient/crypto/KeyPair.java +++ b/crypto/src/main/java/com/strategyobject/substrateclient/crypto/KeyPair.java @@ -19,10 +19,10 @@ public static KeyPair fromBytes(byte @NonNull [] data) { } public SecretKey asSecretKey() { - return SecretKey.fromBytes(Arrays.copyOfRange(getData(), 0, SECRET_KEY_LENGTH)); + return SecretKey.fromBytes(Arrays.copyOfRange(getBytes(), 0, SECRET_KEY_LENGTH)); } public PublicKey asPublicKey() { - return PublicKey.fromBytes(Arrays.copyOfRange(getData(), SECRET_KEY_LENGTH, SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH)); + return PublicKey.fromBytes(Arrays.copyOfRange(getBytes(), SECRET_KEY_LENGTH, SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH)); } } diff --git a/crypto/src/main/java/com/strategyobject/substrateclient/crypto/KeyRing.java b/crypto/src/main/java/com/strategyobject/substrateclient/crypto/KeyRing.java index 5a15c280..d587e45f 100644 --- a/crypto/src/main/java/com/strategyobject/substrateclient/crypto/KeyRing.java +++ b/crypto/src/main/java/com/strategyobject/substrateclient/crypto/KeyRing.java @@ -1,5 +1,6 @@ package com.strategyobject.substrateclient.crypto; +import com.strategyobject.substrateclient.common.types.Bytes; import com.strategyobject.substrateclient.crypto.sr25519.Sr25519NativeCryptoProvider; import lombok.Getter; import lombok.NonNull; @@ -32,15 +33,15 @@ public static KeyRing fromSeed(@NonNull Seed seed) { return new KeyRing(seed); } - public SignatureData sign(@NonNull Signable message) { + public SignatureData sign(@NonNull Bytes message) { return cryptoProvider.sign(publicKey, secretKey, message); } - public boolean verifyOwn(@NonNull SignatureData signature, @NonNull Signable message) { + public boolean verifyOwn(@NonNull SignatureData signature, @NonNull Bytes message) { return cryptoProvider.verify(signature, message, publicKey); } - public boolean verify(@NonNull SignatureData signature, @NonNull Signable message, @NonNull PublicKey publicKey) { + public boolean verify(@NonNull SignatureData signature, @NonNull Bytes message, @NonNull PublicKey publicKey) { return cryptoProvider.verify(signature, message, publicKey); } } diff --git a/crypto/src/main/java/com/strategyobject/substrateclient/crypto/Signable.java b/crypto/src/main/java/com/strategyobject/substrateclient/crypto/Signable.java deleted file mode 100644 index 2826244e..00000000 --- a/crypto/src/main/java/com/strategyobject/substrateclient/crypto/Signable.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.strategyobject.substrateclient.crypto; - -import lombok.NonNull; - -public interface Signable { - byte @NonNull [] getBytes(); -} diff --git a/crypto/src/main/java/com/strategyobject/substrateclient/crypto/sr25519/Sr25519NativeCryptoProvider.java b/crypto/src/main/java/com/strategyobject/substrateclient/crypto/sr25519/Sr25519NativeCryptoProvider.java index b793fa68..56478a8f 100644 --- a/crypto/src/main/java/com/strategyobject/substrateclient/crypto/sr25519/Sr25519NativeCryptoProvider.java +++ b/crypto/src/main/java/com/strategyobject/substrateclient/crypto/sr25519/Sr25519NativeCryptoProvider.java @@ -1,5 +1,6 @@ package com.strategyobject.substrateclient.crypto.sr25519; +import com.strategyobject.substrateclient.common.types.Bytes; import com.strategyobject.substrateclient.crypto.*; import lombok.NonNull; @@ -7,25 +8,25 @@ public class Sr25519NativeCryptoProvider implements CryptoProvider { @Override public KeyPair createPairFromSeed(@NonNull Seed seed) { try { - return KeyPair.fromBytes(Native.fromSeed(seed.getData())); + return KeyPair.fromBytes(Native.fromSeed(seed.getBytes())); } catch (NativeException e) { throw new RuntimeException(e); } } @Override - public SignatureData sign(@NonNull PublicKey publicKey, @NonNull SecretKey secretKey, @NonNull Signable message) { + public SignatureData sign(@NonNull PublicKey publicKey, @NonNull SecretKey secretKey, @NonNull Bytes message) { try { - return SignatureData.fromBytes(Native.sign(publicKey.getData(), secretKey.getData(), message.getBytes())); + return SignatureData.fromBytes(Native.sign(publicKey.getBytes(), secretKey.getBytes(), message.getBytes())); } catch (NativeException e) { throw new RuntimeException(e); } } @Override - public boolean verify(@NonNull SignatureData signature, @NonNull Signable message, @NonNull PublicKey publicKey) { + public boolean verify(@NonNull SignatureData signature, @NonNull Bytes message, @NonNull PublicKey publicKey) { try { - return Native.verify(signature.getData(), message.getBytes(), publicKey.getData()); + return Native.verify(signature.getBytes(), message.getBytes(), publicKey.getBytes()); } catch (NativeException e) { throw new RuntimeException(e); } diff --git a/crypto/src/test/java/com/strategyobject/substrateclient/crypto/sr25519/NativeTests.java b/crypto/src/test/java/com/strategyobject/substrateclient/crypto/sr25519/NativeTests.java index 0955a873..3f428916 100644 --- a/crypto/src/test/java/com/strategyobject/substrateclient/crypto/sr25519/NativeTests.java +++ b/crypto/src/test/java/com/strategyobject/substrateclient/crypto/sr25519/NativeTests.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.crypto.sr25519; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.crypto.NativeException; import lombok.val; import org.junit.jupiter.api.Test; diff --git a/crypto/src/test/java/com/strategyobject/substrateclient/crypto/ss58/SS58CodecTests.java b/crypto/src/test/java/com/strategyobject/substrateclient/crypto/ss58/SS58CodecTests.java index b2d0d20d..77477f90 100644 --- a/crypto/src/test/java/com/strategyobject/substrateclient/crypto/ss58/SS58CodecTests.java +++ b/crypto/src/test/java/com/strategyobject/substrateclient/crypto/ss58/SS58CodecTests.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.crypto.ss58; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; diff --git a/pallet/build.gradle b/pallet/build.gradle index 07e06440..d4a6d4ae 100644 --- a/pallet/build.gradle +++ b/pallet/build.gradle @@ -10,7 +10,7 @@ dependencies { testAnnotationProcessor project(':rpc:rpc-codegen') - testImplementation 'org.testcontainers:testcontainers:1.17.1' - testImplementation 'org.testcontainers:junit-jupiter:1.17.1' + testImplementation 'org.testcontainers:testcontainers:1.17.2' + testImplementation 'org.testcontainers:junit-jupiter:1.17.2' testImplementation 'ch.qos.logback:logback-classic:1.2.11' } \ No newline at end of file diff --git a/pallet/pallet-codegen/src/main/java/com/strategyobject/substrateclient/pallet/codegen/PalletAnnotatedInterface.java b/pallet/pallet-codegen/src/main/java/com/strategyobject/substrateclient/pallet/codegen/PalletAnnotatedInterface.java index 99c3ce8f..bbb10371 100644 --- a/pallet/pallet-codegen/src/main/java/com/strategyobject/substrateclient/pallet/codegen/PalletAnnotatedInterface.java +++ b/pallet/pallet-codegen/src/main/java/com/strategyobject/substrateclient/pallet/codegen/PalletAnnotatedInterface.java @@ -9,6 +9,8 @@ import com.strategyobject.substrateclient.common.codegen.ProcessorContext; import com.strategyobject.substrateclient.pallet.annotation.Pallet; import com.strategyobject.substrateclient.rpc.api.section.State; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.val; import javax.lang.model.element.Element; @@ -16,9 +18,9 @@ import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import java.io.IOException; +import java.util.stream.Stream; -import static com.strategyobject.substrateclient.pallet.codegen.Constants.CLASS_NAME_TEMPLATE; -import static com.strategyobject.substrateclient.pallet.codegen.Constants.STATE; +import static com.strategyobject.substrateclient.pallet.codegen.Constants.*; public class PalletAnnotatedInterface { private final TypeElement interfaceElement; @@ -55,7 +57,9 @@ public void generateClass(ProcessorContext context) throws ProcessingException, val typeSpecBuilder = TypeSpec.classBuilder(className) .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addSuperinterface(TypeName.get(interfaceElement.asType())) - .addField(State.class, STATE, Modifier.FINAL, Modifier.PRIVATE); + .addField(ScaleReaderRegistry.class, SCALE_READER_REGISTRY, Modifier.PRIVATE, Modifier.FINAL) + .addField(ScaleWriterRegistry.class, SCALE_WRITER_REGISTRY, Modifier.PRIVATE, Modifier.FINAL) + .addField(State.class, STATE, Modifier.PRIVATE, Modifier.FINAL); val constructorBuilder = createConstructorBuilder(); @@ -73,12 +77,19 @@ public void generateClass(ProcessorContext context) throws ProcessingException, } private MethodSpec.Builder createConstructorBuilder() { - return MethodSpec.constructorBuilder() + val ctor = MethodSpec.constructorBuilder() .addModifiers(Modifier.PUBLIC) - .addParameter(State.class, STATE) - .beginControlFlow("if ($L == null)", STATE) - .addStatement("throw new $T(\"$L can't be null.\")", IllegalArgumentException.class, STATE) - .endControlFlow() - .addStatement("this.$1L = $1L", STATE); + .addParameter(ScaleReaderRegistry.class, SCALE_READER_REGISTRY) + .addParameter(ScaleWriterRegistry.class, SCALE_WRITER_REGISTRY) + .addParameter(State.class, STATE); + + Stream.of(SCALE_READER_REGISTRY, SCALE_WRITER_REGISTRY, STATE) + .forEach(x -> + ctor.beginControlFlow("if ($L == null)", x) + .addStatement("throw new $T(\"$L can't be null.\")", IllegalArgumentException.class, x) + .endControlFlow() + .addStatement("this.$1L = $1L", x)); + + return ctor; } } diff --git a/pallet/pallet-codegen/src/main/java/com/strategyobject/substrateclient/pallet/codegen/StorageProcessor.java b/pallet/pallet-codegen/src/main/java/com/strategyobject/substrateclient/pallet/codegen/StorageProcessor.java index ca1d58e4..799865c3 100644 --- a/pallet/pallet-codegen/src/main/java/com/strategyobject/substrateclient/pallet/codegen/StorageProcessor.java +++ b/pallet/pallet-codegen/src/main/java/com/strategyobject/substrateclient/pallet/codegen/StorageProcessor.java @@ -19,8 +19,6 @@ import com.strategyobject.substrateclient.scale.codegen.ScaleAnnotationParser; import com.strategyobject.substrateclient.scale.codegen.reader.ReaderCompositor; import com.strategyobject.substrateclient.scale.codegen.writer.WriterCompositor; -import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; -import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.NonNull; import lombok.val; import lombok.var; @@ -104,8 +102,6 @@ private MethodSpec backFieldInitializer(String palletName, .addAnnotation(suppressWarnings("unchecked", "rawtypes")) .returns(TypeName.get(returnType)); - declareReaderAndWriterRegistries(methodSpecBuilder); - val scaleAnnotationParser = new ScaleAnnotationParser(context); val readerCompositor = ReaderCompositor.disallowOpenGeneric( context, @@ -174,7 +170,7 @@ private void assignKeyProvider(MethodSpec.Builder methodSpecBuilder, WriterCompositor writerCompositor, ProcessorContext context) throws ProcessingException { val storageName = AnnotationUtils.getValueFromAnnotation(storageAnnotation, - "value"); + "name"); methodSpecBuilder.addStatement("$1T $2L = $1T.$3L($4S, $5S)", StorageKeyProvider.class, @@ -422,7 +418,7 @@ private void validateKeys(ExecutableElement method, AnnotationMirror storageAnno private void ensureNameIsSet(ExecutableElement method, AnnotationMirror storageAnnotation) throws ProcessingException { val name = AnnotationUtils.getValueFromAnnotation(storageAnnotation, - "value"); + "name"); if (Strings.isNullOrEmpty(name)) { throw new ProcessingException( palletElement, @@ -432,10 +428,4 @@ private void ensureNameIsSet(ExecutableElement method, AnnotationMirror storageA method.getSimpleName()); } } - - private void declareReaderAndWriterRegistries(MethodSpec.Builder methodSpecBuilder) { - methodSpecBuilder - .addStatement("$1T $2L = $1T.getInstance()", ScaleReaderRegistry.class, SCALE_READER_REGISTRY) - .addStatement("$1T $2L = $1T.getInstance()", ScaleWriterRegistry.class, SCALE_WRITER_REGISTRY); - } } diff --git a/pallet/pallet-codegen/src/test/java/com/strategyobject/substrateclient/pallet/codegen/PalletInterfaceProcessorTests.java b/pallet/pallet-codegen/src/test/java/com/strategyobject/substrateclient/pallet/codegen/PalletInterfaceProcessorTests.java index 7d6ca8fd..7ab6a739 100644 --- a/pallet/pallet-codegen/src/test/java/com/strategyobject/substrateclient/pallet/codegen/PalletInterfaceProcessorTests.java +++ b/pallet/pallet-codegen/src/test/java/com/strategyobject/substrateclient/pallet/codegen/PalletInterfaceProcessorTests.java @@ -2,7 +2,6 @@ import com.google.testing.compile.Compilation; import com.google.testing.compile.JavaFileObjects; -import com.strategyobject.substrateclient.pallet.codegen.PalletInterfaceProcessor; import lombok.val; import org.junit.jupiter.api.Test; @@ -99,12 +98,13 @@ void compiles() { assertThat(compilation).succeeded(); + assertContains(generatedName, compilation, "private final ScaleReaderRegistry scaleReaderRegistry;"); + assertContains(generatedName, compilation, "private final ScaleWriterRegistry scaleWriterRegistry;"); assertContains(generatedName, compilation, "private final State state;"); assertContains(generatedName, compilation, "private final StorageNMap value;"); assertContains(generatedName, compilation, "private final StorageNMap map;"); assertContains(generatedName, compilation, "private final StorageNMap doubleMap;"); assertContains(generatedName, compilation, "private final StorageNMap tripleMap;"); - assertContains(generatedName, compilation, "public TestPalletImpl(State state)"); assertContains(generatedName, compilation, "public StorageNMap value()"); assertContains(generatedName, compilation, "public StorageNMap map()"); assertContains(generatedName, compilation, "public StorageNMap doubleMap()"); diff --git a/pallet/pallet-codegen/src/test/resources/AmbiguousScale.java b/pallet/pallet-codegen/src/test/resources/AmbiguousScale.java index fc71d620..bc58894a 100644 --- a/pallet/pallet-codegen/src/test/resources/AmbiguousScale.java +++ b/pallet/pallet-codegen/src/test/resources/AmbiguousScale.java @@ -9,7 +9,7 @@ @Pallet("Test") public interface AmbiguousScale { - @Storage(value = "Test", keys = { + @Storage(name = "Test", keys = { @StorageKey( hasher = StorageHasher.BLAKE2_128_CONCAT, type = @Scale(ScaleType.I32.class), diff --git a/pallet/pallet-codegen/src/test/resources/ClassPallet.java b/pallet/pallet-codegen/src/test/resources/ClassPallet.java index c9457072..e1b1658c 100644 --- a/pallet/pallet-codegen/src/test/resources/ClassPallet.java +++ b/pallet/pallet-codegen/src/test/resources/ClassPallet.java @@ -4,6 +4,6 @@ @Pallet("Class") public abstract class ClassPallet { - @Storage("Test") + @Storage(name = "Test") public abstract StorageNMap test(); } diff --git a/pallet/pallet-codegen/src/test/resources/NotAStorage.java b/pallet/pallet-codegen/src/test/resources/NotAStorage.java index acb153eb..5b4b802e 100644 --- a/pallet/pallet-codegen/src/test/resources/NotAStorage.java +++ b/pallet/pallet-codegen/src/test/resources/NotAStorage.java @@ -7,7 +7,7 @@ @Pallet("Test") public interface NotAStorage { - @Storage(value = "Test", keys = { + @Storage(name = "Test", keys = { @StorageKey( hasher = StorageHasher.BLAKE2_128_CONCAT, type = @Scale(ScaleType.I32.class) diff --git a/pallet/pallet-codegen/src/test/resources/TestPallet.java b/pallet/pallet-codegen/src/test/resources/TestPallet.java index 45aa9330..fcb0d8b3 100644 --- a/pallet/pallet-codegen/src/test/resources/TestPallet.java +++ b/pallet/pallet-codegen/src/test/resources/TestPallet.java @@ -11,11 +11,11 @@ @Pallet("Test") public interface TestPallet { - @Storage("Value") + @Storage(name = "Value") StorageNMap value(); @Storage( - value = "Map", + name = "Map", keys = { @StorageKey(type = @Scale(ScaleType.I32.class), hasher = StorageHasher.TWOX_64_CONCAT) @@ -23,7 +23,7 @@ public interface TestPallet { StorageNMap map(); @Storage( - value = "DoubleMap", + name = "DoubleMap", keys = { @StorageKey(type = @Scale(ScaleType.I32.class), hasher = StorageHasher.TWOX_64_CONCAT), @@ -42,7 +42,7 @@ public interface TestPallet { StorageNMap doubleMap(); @Storage( - value = "TripleMap", + name = "TripleMap", keys = { @StorageKey(type = @Scale(String.class), hasher = StorageHasher.BLAKE2_128_CONCAT), diff --git a/pallet/pallet-codegen/src/test/resources/UnnamedPallet.java b/pallet/pallet-codegen/src/test/resources/UnnamedPallet.java index d698b520..c9371485 100644 --- a/pallet/pallet-codegen/src/test/resources/UnnamedPallet.java +++ b/pallet/pallet-codegen/src/test/resources/UnnamedPallet.java @@ -4,6 +4,6 @@ @Pallet("") public interface UnnamedPallet { - @Storage("Test") + @Storage(name = "Test") StorageNMap test(); } diff --git a/pallet/pallet-codegen/src/test/resources/UnnamedStorage.java b/pallet/pallet-codegen/src/test/resources/UnnamedStorage.java index 680dff5c..64e1e03b 100644 --- a/pallet/pallet-codegen/src/test/resources/UnnamedStorage.java +++ b/pallet/pallet-codegen/src/test/resources/UnnamedStorage.java @@ -4,6 +4,6 @@ @Pallet("Test") public interface UnnamedStorage { - @Storage("") + @Storage(name = "") StorageNMap unnamed(); } diff --git a/pallet/pallet-codegen/src/test/resources/WithoutScale.java b/pallet/pallet-codegen/src/test/resources/WithoutScale.java index 463027ca..299a706b 100644 --- a/pallet/pallet-codegen/src/test/resources/WithoutScale.java +++ b/pallet/pallet-codegen/src/test/resources/WithoutScale.java @@ -6,7 +6,7 @@ @Pallet("Test") public interface WithoutScale { - @Storage(value = "Test", keys = { + @Storage(name = "Test", keys = { @StorageKey(hasher = StorageHasher.BLAKE2_128_CONCAT) }) StorageNMap test(); diff --git a/pallet/src/main/java/com/strategyobject/substrateclient/pallet/GeneratedPalletResolver.java b/pallet/src/main/java/com/strategyobject/substrateclient/pallet/GeneratedPalletFactory.java similarity index 60% rename from pallet/src/main/java/com/strategyobject/substrateclient/pallet/GeneratedPalletResolver.java rename to pallet/src/main/java/com/strategyobject/substrateclient/pallet/GeneratedPalletFactory.java index 0243fa4b..c4023073 100644 --- a/pallet/src/main/java/com/strategyobject/substrateclient/pallet/GeneratedPalletResolver.java +++ b/pallet/src/main/java/com/strategyobject/substrateclient/pallet/GeneratedPalletFactory.java @@ -2,17 +2,22 @@ import com.strategyobject.substrateclient.pallet.annotation.Pallet; import com.strategyobject.substrateclient.rpc.api.section.State; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.val; -@RequiredArgsConstructor(staticName = "with") -public class GeneratedPalletResolver implements PalletResolver { +@RequiredArgsConstructor +public class GeneratedPalletFactory implements PalletFactory { private static final String CLASS_NAME_TEMPLATE = "%sImpl"; + + private final @NonNull ScaleReaderRegistry scaleReaderRegistry; + private final @NonNull ScaleWriterRegistry scaleWriterRegistry; private final @NonNull State state; @Override - public T resolve(Class interfaceClass) { + public T create(Class interfaceClass) { if (interfaceClass.getDeclaredAnnotationsByType(Pallet.class).length == 0) { throw new IllegalArgumentException( String.format("%s can't be constructed because it is not annotated with @%s.", @@ -23,9 +28,9 @@ public T resolve(Class interfaceClass) { Class implClazz; try { implClazz = Class.forName(String.format(CLASS_NAME_TEMPLATE, interfaceClass.getCanonicalName())); - val ctor = implClazz.getConstructor(State.class); + val ctor = implClazz.getConstructor(ScaleReaderRegistry.class, ScaleWriterRegistry.class, State.class); - return interfaceClass.cast(ctor.newInstance(state)); + return interfaceClass.cast(ctor.newInstance(scaleReaderRegistry, scaleWriterRegistry, state)); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } diff --git a/pallet/src/main/java/com/strategyobject/substrateclient/pallet/PalletFactory.java b/pallet/src/main/java/com/strategyobject/substrateclient/pallet/PalletFactory.java new file mode 100644 index 00000000..b3f26ff8 --- /dev/null +++ b/pallet/src/main/java/com/strategyobject/substrateclient/pallet/PalletFactory.java @@ -0,0 +1,5 @@ +package com.strategyobject.substrateclient.pallet; + +public interface PalletFactory { + T create(Class clazz); +} diff --git a/pallet/src/main/java/com/strategyobject/substrateclient/pallet/PalletResolver.java b/pallet/src/main/java/com/strategyobject/substrateclient/pallet/PalletResolver.java deleted file mode 100644 index 22bfeec7..00000000 --- a/pallet/src/main/java/com/strategyobject/substrateclient/pallet/PalletResolver.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.strategyobject.substrateclient.pallet; - -public interface PalletResolver { - T resolve(Class clazz); -} diff --git a/pallet/src/main/java/com/strategyobject/substrateclient/pallet/annotation/Storage.java b/pallet/src/main/java/com/strategyobject/substrateclient/pallet/annotation/Storage.java index b334d5ed..4db7e3f6 100644 --- a/pallet/src/main/java/com/strategyobject/substrateclient/pallet/annotation/Storage.java +++ b/pallet/src/main/java/com/strategyobject/substrateclient/pallet/annotation/Storage.java @@ -14,7 +14,7 @@ /** * @return the name of a storage */ - String value(); + String name(); /** * @return the array of items that describe SCALE-codecs diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/GeneratedPalletResolverTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/GeneratedPalletFactoryTests.java similarity index 54% rename from pallet/src/test/java/com/strategyobject/substrateclient/pallet/GeneratedPalletResolverTests.java rename to pallet/src/test/java/com/strategyobject/substrateclient/pallet/GeneratedPalletFactoryTests.java index 15b95768..15d99c55 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/GeneratedPalletResolverTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/GeneratedPalletFactoryTests.java @@ -7,33 +7,27 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.mock; -class GeneratedPalletResolverTests { +class GeneratedPalletFactoryTests { + private final GeneratedPalletFactory factory = new GeneratedPalletFactory( + TestsHelper.SCALE_READER_REGISTRY, + TestsHelper.SCALE_WRITER_REGISTRY, + mock(State.class)); + @Test void throwsWhenPalletIsNotAnnotated() { - val state = mock(State.class); - - val resolver = GeneratedPalletResolver.with(state); - assertThrows(IllegalArgumentException.class, - () -> resolver.resolve(TestPalletNotAnnotated.class)); + () -> factory.create(TestPalletNotAnnotated.class)); } @Test void throwsWhenPalletImplementationDoesNotHaveAppropriateConstructor() { - val state = mock(State.class); - - val resolver = GeneratedPalletResolver.with(state); - assertThrows(RuntimeException.class, - () -> resolver.resolve(TestPalletWithoutConstructor.class)); + () -> factory.create(TestPalletWithoutConstructor.class)); } @Test void resolve() { - val state = mock(State.class); - - val resolver = GeneratedPalletResolver.with(state); - val pallet = resolver.resolve(TestPallet.class); + val pallet = factory.create(TestPallet.class); assertNotNull(pallet); assertEquals(TestPalletImpl.class, pallet.getClass()); diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/TestPalletImpl.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/TestPalletImpl.java index 52d9538e..6fd372b9 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/TestPalletImpl.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/TestPalletImpl.java @@ -1,9 +1,13 @@ package com.strategyobject.substrateclient.pallet; import com.strategyobject.substrateclient.rpc.api.section.State; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public class TestPalletImpl implements TestPallet { + private final ScaleReaderRegistry scaleReaderRegistry; + private final ScaleWriterRegistry scaleWriterRegistry; private final State state; } diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/TestsHelper.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/TestsHelper.java new file mode 100644 index 00000000..8081974d --- /dev/null +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/TestsHelper.java @@ -0,0 +1,36 @@ +package com.strategyobject.substrateclient.pallet; + +import com.strategyobject.substrateclient.rpc.GeneratedRpcSectionFactory; +import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry; +import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import com.strategyobject.substrateclient.transport.ProviderInterface; + +public class TestsHelper { + public static final ScaleReaderRegistry SCALE_READER_REGISTRY = new ScaleReaderRegistry() {{ + registerAnnotatedFrom("com.strategyobject.substrateclient"); + }}; + + public static final ScaleWriterRegistry SCALE_WRITER_REGISTRY = new ScaleWriterRegistry() {{ + registerAnnotatedFrom("com.strategyobject.substrateclient"); + }}; + + public static final RpcEncoderRegistry RPC_ENCODER_REGISTRY = new RpcEncoderRegistry(SCALE_WRITER_REGISTRY) {{ + registerAnnotatedFrom("com.strategyobject.substrateclient"); + }}; + + public static final RpcDecoderRegistry RPC_DECODER_REGISTRY = new RpcDecoderRegistry(SCALE_READER_REGISTRY) {{ + registerAnnotatedFrom("com.strategyobject.substrateclient"); + }}; + + public static GeneratedRpcSectionFactory createSectionFactory(ProviderInterface provider) { + return new GeneratedRpcSectionFactory( + provider, + RPC_ENCODER_REGISTRY, + SCALE_WRITER_REGISTRY, + RPC_DECODER_REGISTRY, + SCALE_READER_REGISTRY); + } +} + diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/Blake2B128ConcatTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/Blake2B128ConcatTests.java index 5cc48f58..c0cc7780 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/Blake2B128ConcatTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/Blake2B128ConcatTests.java @@ -1,10 +1,10 @@ package com.strategyobject.substrateclient.pallet.storage; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.crypto.ss58.SS58Codec; +import com.strategyobject.substrateclient.pallet.TestsHelper; import com.strategyobject.substrateclient.rpc.api.AccountId; import com.strategyobject.substrateclient.scale.ScaleWriter; -import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; @@ -42,7 +42,7 @@ private static Stream getTestCasesForGetHash() { @SuppressWarnings("unchecked") private static byte[] decode(Class type, T value) { val buf = new ByteArrayOutputStream(); - ((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(type)).write(value, buf); + ((ScaleWriter) TestsHelper.SCALE_WRITER_REGISTRY.resolve(type)).write(value, buf); return buf.toByteArray(); } diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/IdentityTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/IdentityTests.java index 11304829..efcc9991 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/IdentityTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/IdentityTests.java @@ -1,9 +1,9 @@ package com.strategyobject.substrateclient.pallet.storage; +import com.strategyobject.substrateclient.pallet.TestsHelper; import com.strategyobject.substrateclient.rpc.api.BlockHash; import com.strategyobject.substrateclient.rpc.api.impl.Hash256; import com.strategyobject.substrateclient.scale.ScaleWriter; -import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; @@ -29,7 +29,7 @@ private static Stream getTestCasesForGetHash() { @SuppressWarnings("unchecked") private static byte[] encode(Class type, T value) { val buf = new ByteArrayOutputStream(); - ((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(type)).write(value, buf); + ((ScaleWriter) TestsHelper.SCALE_WRITER_REGISTRY.resolve(type)).write(value, buf); return buf.toByteArray(); } diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/KeyHasherTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/KeyHasherTests.java index 03b6b7aa..9180264e 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/KeyHasherTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/KeyHasherTests.java @@ -1,15 +1,14 @@ package com.strategyobject.substrateclient.pallet.storage; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.crypto.ss58.SS58Codec; +import com.strategyobject.substrateclient.pallet.TestsHelper; import com.strategyobject.substrateclient.rpc.api.AccountId; import com.strategyobject.substrateclient.rpc.api.BlockHash; import com.strategyobject.substrateclient.rpc.api.impl.Hash256; import com.strategyobject.substrateclient.scale.ScaleReader; import com.strategyobject.substrateclient.scale.ScaleWriter; import com.strategyobject.substrateclient.scale.readers.CompactIntegerReader; -import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; -import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import com.strategyobject.substrateclient.scale.writers.CompactIntegerWriter; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; @@ -29,8 +28,8 @@ private static Stream getTestCasesForGetHash() { return Stream.of( Arguments.of( 10, - ScaleReaderRegistry.getInstance().resolve(Integer.class), - ScaleWriterRegistry.getInstance().resolve(Integer.class), + TestsHelper.SCALE_READER_REGISTRY.resolve(Integer.class), + TestsHelper.SCALE_WRITER_REGISTRY.resolve(Integer.class), TwoX64Concat.getInstance(), "0xa6b274250e6753f00a000000" ), @@ -39,15 +38,15 @@ private static Stream getTestCasesForGetHash() { SS58Codec.decode( "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty") .getAddress()), - ScaleReaderRegistry.getInstance().resolve(AccountId.class), - ScaleWriterRegistry.getInstance().resolve(AccountId.class), + TestsHelper.SCALE_READER_REGISTRY.resolve(AccountId.class), + TestsHelper.SCALE_WRITER_REGISTRY.resolve(AccountId.class), Blake2B128Concat.getInstance(), "0x4f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48" ), Arguments.of( Hash256.fromBytes(HexConverter.toBytes("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")), - ScaleReaderRegistry.getInstance().resolve(BlockHash.class), - ScaleWriterRegistry.getInstance().resolve(BlockHash.class), + TestsHelper.SCALE_READER_REGISTRY.resolve(BlockHash.class), + TestsHelper.SCALE_WRITER_REGISTRY.resolve(BlockHash.class), Identity.getInstance(), "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" ) @@ -60,8 +59,8 @@ private static Stream getTestCasesForExtractKey() { new ByteArrayInputStream( HexConverter.toBytes("0x5153cb1f00942ff401000000") ), - ScaleReaderRegistry.getInstance().resolve(Integer.class), - ScaleWriterRegistry.getInstance().resolve(Integer.class), + TestsHelper.SCALE_READER_REGISTRY.resolve(Integer.class), + TestsHelper.SCALE_WRITER_REGISTRY.resolve(Integer.class), TwoX64Concat.getInstance(), 1, 0 @@ -70,8 +69,8 @@ private static Stream getTestCasesForExtractKey() { new ByteArrayInputStream( HexConverter.toBytes("0x969e061847da7e84337ea78dc577cd1d05000000") ), - ScaleReaderRegistry.getInstance().resolve(Integer.class), - ScaleWriterRegistry.getInstance().resolve(Integer.class), + TestsHelper.SCALE_READER_REGISTRY.resolve(Integer.class), + TestsHelper.SCALE_WRITER_REGISTRY.resolve(Integer.class), Blake2B128Concat.getInstance(), 5, 0 @@ -90,8 +89,8 @@ private static Stream getTestCasesForExtractKey() { new ByteArrayInputStream( HexConverter.toBytes("0x") ), - ScaleReaderRegistry.getInstance().resolve(Void.class), - ScaleWriterRegistry.getInstance().resolve(Void.class), + TestsHelper.SCALE_READER_REGISTRY.resolve(Void.class), + TestsHelper.SCALE_WRITER_REGISTRY.resolve(Void.class), Identity.getInstance(), null, 0 @@ -101,8 +100,8 @@ private static Stream getTestCasesForExtractKey() { HexConverter.toBytes("0x4f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48" + "a6b274250e6753f00a000000") ), - ScaleReaderRegistry.getInstance().resolve(AccountId.class), - ScaleWriterRegistry.getInstance().resolve(AccountId.class), + TestsHelper.SCALE_READER_REGISTRY.resolve(AccountId.class), + TestsHelper.SCALE_WRITER_REGISTRY.resolve(AccountId.class), Blake2B128Concat.getInstance(), AccountId.fromBytes( SS58Codec.decode( @@ -113,8 +112,8 @@ private static Stream getTestCasesForExtractKey() { Arguments.of( new ByteArrayInputStream( HexConverter.toBytes("0xabcdef98765432100123456789abcdefabcdef98765432100123456789abcdef")), - ScaleReaderRegistry.getInstance().resolve(BlockHash.class), - ScaleWriterRegistry.getInstance().resolve(BlockHash.class), + TestsHelper.SCALE_READER_REGISTRY.resolve(BlockHash.class), + TestsHelper.SCALE_WRITER_REGISTRY.resolve(BlockHash.class), Identity.getInstance(), Hash256.fromBytes(HexConverter.toBytes("0xabcdef98765432100123456789abcdefabcdef98765432100123456789abcdef")), 0 @@ -122,8 +121,8 @@ private static Stream getTestCasesForExtractKey() { Arguments.of( new ByteArrayInputStream( HexConverter.toBytes("0x518366b5b1bc7c99d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d")), - ScaleReaderRegistry.getInstance().resolve(BlockHash.class), - ScaleWriterRegistry.getInstance().resolve(BlockHash.class), + TestsHelper.SCALE_READER_REGISTRY.resolve(BlockHash.class), + TestsHelper.SCALE_WRITER_REGISTRY.resolve(BlockHash.class), TwoX64Concat.getInstance(), AccountId.fromBytes( SS58Codec.decode( diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageDoubleMapImplTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageDoubleMapImplTests.java index 1cffdbb7..722a76f2 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageDoubleMapImplTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageDoubleMapImplTests.java @@ -1,13 +1,11 @@ package com.strategyobject.substrateclient.pallet.storage; import com.strategyobject.substrateclient.crypto.ss58.SS58Codec; -import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; +import com.strategyobject.substrateclient.pallet.TestsHelper; import com.strategyobject.substrateclient.rpc.api.AccountId; import com.strategyobject.substrateclient.rpc.api.section.State; import com.strategyobject.substrateclient.scale.ScaleReader; import com.strategyobject.substrateclient.scale.ScaleWriter; -import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; -import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; import com.strategyobject.substrateclient.tests.containers.TestSubstrateContainer; import com.strategyobject.substrateclient.transport.ws.WsProvider; @@ -35,16 +33,17 @@ void societyVotes() throws Exception { .build()) { wsProvider.connect().get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS); - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val storage = StorageDoubleMapImpl.with( state, - (ScaleReader) ScaleReaderRegistry.getInstance().resolve(Void.class), + (ScaleReader) TestsHelper.SCALE_READER_REGISTRY.resolve(Void.class), StorageKeyProvider.of("Society", "Votes") - .use(KeyHasher.with((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(AccountId.class), - (ScaleReader) ScaleReaderRegistry.getInstance().resolve(AccountId.class), + .use( + KeyHasher.with((ScaleWriter) TestsHelper.SCALE_WRITER_REGISTRY.resolve(AccountId.class), + (ScaleReader) TestsHelper.SCALE_READER_REGISTRY.resolve(AccountId.class), TwoX64Concat.getInstance()), - KeyHasher.with((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(AccountId.class), - (ScaleReader) ScaleReaderRegistry.getInstance().resolve(AccountId.class), + KeyHasher.with((ScaleWriter) TestsHelper.SCALE_WRITER_REGISTRY.resolve(AccountId.class), + (ScaleReader) TestsHelper.SCALE_READER_REGISTRY.resolve(AccountId.class), TwoX64Concat.getInstance()))); val alice = AccountId.fromBytes( SS58Codec.decode( diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageKeyProviderTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageKeyProviderTests.java index 3baaa0cc..2dc66e4a 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageKeyProviderTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageKeyProviderTests.java @@ -1,13 +1,12 @@ package com.strategyobject.substrateclient.pallet.storage; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.crypto.ss58.SS58Codec; +import com.strategyobject.substrateclient.pallet.TestsHelper; import com.strategyobject.substrateclient.rpc.api.AccountId; import com.strategyobject.substrateclient.rpc.api.StorageKey; import com.strategyobject.substrateclient.scale.ScaleReader; import com.strategyobject.substrateclient.scale.ScaleWriter; -import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; -import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.NonNull; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; @@ -45,8 +44,8 @@ private static Stream getTestCasesForGetBySingleKey() { Arguments.of("System", "BlockHash", KeyHasher.with( - (ScaleWriter) ScaleWriterRegistry.getInstance().resolve(Integer.class), - (ScaleReader) ScaleReaderRegistry.getInstance().resolve(Integer.class), + (ScaleWriter) TestsHelper.SCALE_WRITER_REGISTRY.resolve(Integer.class), + (ScaleReader) TestsHelper.SCALE_READER_REGISTRY.resolve(Integer.class), TwoX64Concat.getInstance() ), 2, @@ -59,12 +58,12 @@ private static Stream getTestCasesForGetBySingleKey() { @SuppressWarnings({"unchecked", "SameParameterValue"}) private static ScaleReader resolveReader(Class clazz) { - return (ScaleReader) ScaleReaderRegistry.getInstance().resolve(clazz); + return (ScaleReader) TestsHelper.SCALE_READER_REGISTRY.resolve(clazz); } @SuppressWarnings({"unchecked", "SameParameterValue"}) private static ScaleWriter resolveWriter(Class clazz) { - return (ScaleWriter) ScaleWriterRegistry.getInstance().resolve(clazz); + return (ScaleWriter) TestsHelper.SCALE_WRITER_REGISTRY.resolve(clazz); } private static Stream getTestCasesForGetByDoubleKey() { diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageMapImplTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageMapImplTests.java index bcf1f6c1..37fda4f8 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageMapImplTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageMapImplTests.java @@ -1,12 +1,10 @@ package com.strategyobject.substrateclient.pallet.storage; -import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; +import com.strategyobject.substrateclient.pallet.TestsHelper; import com.strategyobject.substrateclient.rpc.api.BlockHash; import com.strategyobject.substrateclient.rpc.api.section.State; import com.strategyobject.substrateclient.scale.ScaleReader; import com.strategyobject.substrateclient.scale.ScaleWriter; -import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; -import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; import com.strategyobject.substrateclient.tests.containers.TestSubstrateContainer; import com.strategyobject.substrateclient.transport.ws.WsProvider; @@ -35,18 +33,18 @@ void systemBlockHash() throws Exception { .build()) { wsProvider.connect().get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS); - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val storage = StorageMapImpl.with( state, - (ScaleReader) ScaleReaderRegistry.getInstance().resolve(BlockHash.class), + (ScaleReader) TestsHelper.SCALE_READER_REGISTRY.resolve(BlockHash.class), StorageKeyProvider.of("System", "BlockHash") - .use(KeyHasher.with((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(Integer.class), - (ScaleReader) ScaleReaderRegistry.getInstance().resolve(Integer.class), + .use(KeyHasher.with((ScaleWriter) TestsHelper.SCALE_WRITER_REGISTRY.resolve(Integer.class), + (ScaleReader) TestsHelper.SCALE_READER_REGISTRY.resolve(Integer.class), TwoX64Concat.getInstance()))); val actual = storage.get(0).get(); - assertNotEquals(BigInteger.ZERO, new BigInteger(actual.getData())); + assertNotEquals(BigInteger.ZERO, new BigInteger(actual.getBytes())); } } } diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageNMapImplTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageNMapImplTests.java index 638f8732..d16833df 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageNMapImplTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageNMapImplTests.java @@ -2,7 +2,7 @@ import com.strategyobject.substrateclient.common.types.tuple.Pair; import com.strategyobject.substrateclient.crypto.ss58.SS58Codec; -import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; +import com.strategyobject.substrateclient.pallet.TestsHelper; import com.strategyobject.substrateclient.rpc.api.AccountId; import com.strategyobject.substrateclient.rpc.api.BlockHash; import com.strategyobject.substrateclient.rpc.api.BlockNumber; @@ -10,8 +10,6 @@ import com.strategyobject.substrateclient.rpc.api.section.State; import com.strategyobject.substrateclient.scale.ScaleReader; import com.strategyobject.substrateclient.scale.ScaleWriter; -import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; -import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; import com.strategyobject.substrateclient.tests.containers.TestSubstrateContainer; import com.strategyobject.substrateclient.transport.ProviderInterface; @@ -47,10 +45,10 @@ class StorageNMapImplTests { private static StorageNMapImpl newSystemBlockHashStorage(State state) { return StorageNMapImpl.with( state, - (ScaleReader) ScaleReaderRegistry.getInstance().resolve(BlockHash.class), + (ScaleReader) TestsHelper.SCALE_READER_REGISTRY.resolve(BlockHash.class), StorageKeyProvider.of("System", "BlockHash") - .use(KeyHasher.with((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(BlockNumber.class), - (ScaleReader) ScaleReaderRegistry.getInstance().resolve(BlockNumber.class), + .use(KeyHasher.with((ScaleWriter) TestsHelper.SCALE_WRITER_REGISTRY.resolve(BlockNumber.class), + (ScaleReader) TestsHelper.SCALE_READER_REGISTRY.resolve(BlockNumber.class), TwoX64Concat.getInstance()))); } @@ -67,7 +65,7 @@ private WsProvider getConnectedProvider() throws InterruptedException, Execution @Test void keys() throws Exception { try (val wsProvider = getConnectedProvider()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val storage = newSystemBlockHashStorage(state); val collection = storage.keys().get(); @@ -87,17 +85,17 @@ void keys() throws Exception { assertEquals(1, list.size()); val block = (BlockHash) list.stream().findFirst().orElseThrow(RuntimeException::new); - assertNotEquals(BigInteger.ZERO, new BigInteger(block.getData())); + assertNotEquals(BigInteger.ZERO, new BigInteger(block.getBytes())); } } @Test void multiToDifferentStorages() throws Exception { try (val wsProvider = getConnectedProvider()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val storageValue = StorageNMapImpl.with( state, - ScaleReaderRegistry.getInstance().resolve(AccountId.class), + TestsHelper.SCALE_READER_REGISTRY.resolve(AccountId.class), StorageKeyProvider.of("Sudo", "Key")); val storageMap = newSystemBlockHashStorage(state); @@ -124,7 +122,7 @@ void multiToDifferentStorages() throws Exception { @Test void entries() throws Exception { try (val wsProvider = getConnectedProvider()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val storage = newSystemBlockHashStorage(state); val collection = storage.entries().get(); @@ -139,14 +137,14 @@ void entries() throws Exception { })); assertEquals(BlockNumber.GENESIS, blockNumber.get()); - assertNotEquals(BigInteger.ZERO, new BigInteger(blockHash.get().getData())); + assertNotEquals(BigInteger.ZERO, new BigInteger(blockHash.get().getBytes())); } } @Test void multi() throws Exception { try (val wsProvider = getConnectedProvider()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val storage = newSystemBlockHashStorage(state); val collection = storage.multi( @@ -164,7 +162,7 @@ void multi() throws Exception { assertEquals(2, list.size()); assertEquals(BlockNumber.GENESIS, list.get(0).getValue0()); - assertNotEquals(BigInteger.ZERO, new BigInteger(list.get(0).getValue1().getData())); + assertNotEquals(BigInteger.ZERO, new BigInteger(list.get(0).getValue1().getBytes())); assertEquals(BlockNumber.of(1), list.get(1).getValue0()); assertNull(list.get(1).getValue1()); @@ -174,7 +172,7 @@ void multi() throws Exception { @Test void keysPaged() throws Exception { try (val wsProvider = getConnectedProvider()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); waitForNewBlocks(wsProvider); val storage = newSystemBlockHashStorage(state); @@ -200,7 +198,7 @@ void keysPaged() throws Exception { @Test void entriesPaged() throws Exception { try (val wsProvider = getConnectedProvider()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); waitForNewBlocks(wsProvider); val storage = newSystemBlockHashStorage(state); @@ -218,7 +216,7 @@ void entriesPaged() throws Exception { .forEachRemaining(e -> e.consume((value, keys) -> { val key = (BlockNumber) keys.get(0); - assertNotEquals(BigInteger.ZERO, new BigInteger(value.getData())); + assertNotEquals(BigInteger.ZERO, new BigInteger(value.getBytes())); pairs.add(Pair.of(key, value)); })); @@ -236,7 +234,7 @@ void entriesPaged() throws Exception { @Test void subscribe() throws Exception { try (val wsProvider = getConnectedProvider()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val blockNumber = BlockNumber.of(2); val storage = newSystemBlockHashStorage(state); val blockHash = new AtomicReference(); @@ -253,7 +251,7 @@ void subscribe() throws Exception { waitForNewBlocks(wsProvider); - val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + val chain = TestsHelper.createSectionFactory(wsProvider).create(Chain.class); val expectedValue = chain.getBlockHash(blockNumber).join(); val history = storage.history(blockNumber).join(); val changedAt = history.stream() @@ -271,7 +269,7 @@ void subscribe() throws Exception { } private void waitForNewBlocks(ProviderInterface wsProvider) throws Exception { - val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + val chain = TestsHelper.createSectionFactory(wsProvider).create(Chain.class); val blockCount = new AtomicInteger(0); val unsubscribeFunc = chain diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageValueImplTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageValueImplTests.java index c933faf6..74c7a8df 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageValueImplTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/StorageValueImplTests.java @@ -1,12 +1,11 @@ package com.strategyobject.substrateclient.pallet.storage; import com.strategyobject.substrateclient.crypto.ss58.SS58Codec; -import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; +import com.strategyobject.substrateclient.pallet.TestsHelper; import com.strategyobject.substrateclient.rpc.api.AccountId; import com.strategyobject.substrateclient.rpc.api.BlockNumber; import com.strategyobject.substrateclient.rpc.api.section.Chain; import com.strategyobject.substrateclient.rpc.api.section.State; -import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; import com.strategyobject.substrateclient.tests.containers.TestSubstrateContainer; import com.strategyobject.substrateclient.transport.ws.WsProvider; @@ -38,10 +37,10 @@ void sudoKey() throws Exception { .build()) { wsProvider.connect().get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS); - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val storage = StorageValueImpl.with( state, - ScaleReaderRegistry.getInstance().resolve(AccountId.class), + TestsHelper.SCALE_READER_REGISTRY.resolve(AccountId.class), StorageKeyProvider.of("Sudo", "Key")); val actual = storage.get().get(); @@ -62,13 +61,13 @@ void sudoKeyAtGenesis() throws Exception { .disableAutoConnect() .build()) { wsProvider.connect().get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS); - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); - val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); + val chain = TestsHelper.createSectionFactory(wsProvider).create(Chain.class); val blockHash = chain.getBlockHash(BlockNumber.GENESIS).get(); val storage = StorageValueImpl.with( state, - ScaleReaderRegistry.getInstance().resolve(AccountId.class), + TestsHelper.SCALE_READER_REGISTRY.resolve(AccountId.class), StorageKeyProvider.of("Sudo", "Key")); val actual = storage.at(blockHash).get(); diff --git a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/TwoX64ConcatTests.java b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/TwoX64ConcatTests.java index e4e2e8a4..181b9e69 100644 --- a/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/TwoX64ConcatTests.java +++ b/pallet/src/test/java/com/strategyobject/substrateclient/pallet/storage/TwoX64ConcatTests.java @@ -1,10 +1,10 @@ package com.strategyobject.substrateclient.pallet.storage; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.crypto.ss58.SS58Codec; +import com.strategyobject.substrateclient.pallet.TestsHelper; import com.strategyobject.substrateclient.rpc.api.AccountId; import com.strategyobject.substrateclient.scale.ScaleWriter; -import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; @@ -55,7 +55,7 @@ private static Stream getTestCasesForGetHash() { @SuppressWarnings("unchecked") private static byte[] decode(Class type, T value) { val buf = new ByteArrayOutputStream(); - ((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(type)).write(value, buf); + ((ScaleWriter) TestsHelper.SCALE_WRITER_REGISTRY.resolve(type)).write(value, buf); return buf.toByteArray(); } diff --git a/rpc/rpc-api/build.gradle b/rpc/rpc-api/build.gradle index e23e265e..e7b52375 100644 --- a/rpc/rpc-api/build.gradle +++ b/rpc/rpc-api/build.gradle @@ -13,7 +13,7 @@ dependencies { testAnnotationProcessor project(':scale:scale-codegen') testImplementation 'ch.qos.logback:logback-classic:1.2.11' - testImplementation 'org.testcontainers:testcontainers:1.17.1' - testImplementation 'org.testcontainers:junit-jupiter:1.17.1' + testImplementation 'org.testcontainers:testcontainers:1.17.2' + testImplementation 'org.testcontainers:junit-jupiter:1.17.2' testImplementation 'org.awaitility:awaitility:4.2.0' } \ No newline at end of file diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/AccountId.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/AccountId.java index 67ee4b7d..a467f1db 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/AccountId.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/AccountId.java @@ -3,15 +3,12 @@ import com.strategyobject.substrateclient.common.types.FixedBytes; import com.strategyobject.substrateclient.common.types.Size; import com.strategyobject.substrateclient.crypto.ss58.SS58Codec; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; import lombok.NonNull; import lombok.var; import java.util.concurrent.atomic.AtomicReference; -public class AccountId - extends FixedBytes - implements ScaleSelfWritable { +public class AccountId extends FixedBytes { private final AtomicReference encoded = new AtomicReference<>(null); @@ -26,7 +23,7 @@ public String toString() { return result; } - result = SS58Codec.encode(getData(), MetadataRegistry.getInstance().getSS58AddressFormat()); + result = SS58Codec.encode(getBytes(), MetadataRegistry.getInstance().getSS58AddressFormat()); return encoded.compareAndSet(null, result) ? result : encoded.get(); } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/AdditionalExtra.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/AdditionalExtra.java index c3e57d65..9b84fd1a 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/AdditionalExtra.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/AdditionalExtra.java @@ -1,6 +1,4 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; - -public interface AdditionalExtra extends ScaleSelfWritable { +public interface AdditionalExtra { } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Address.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Address.java index 77b67742..844dcf2c 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Address.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Address.java @@ -1,7 +1,5 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; - -public interface Address extends ScaleSelfWritable
{ +public interface Address { AddressKind getKind(); } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/AddressKindWriter.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/AddressKindWriter.java index c041b7c5..870e0dab 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/AddressKindWriter.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/AddressKindWriter.java @@ -5,17 +5,21 @@ import com.strategyobject.substrateclient.scale.annotation.AutoRegister; import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.NonNull; +import lombok.RequiredArgsConstructor; import java.io.IOException; import java.io.OutputStream; @AutoRegister(types = AddressKind.class) +@RequiredArgsConstructor public class AddressKindWriter implements ScaleWriter { + private final @NonNull ScaleWriterRegistry registry; + @Override @SuppressWarnings("unchecked") public void write(@NonNull AddressKind value, @NonNull OutputStream stream, ScaleWriter... writers) throws IOException { Preconditions.checkArgument(writers == null || writers.length == 0); - ((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(byte.class)).write(value.getValue(), stream); + ((ScaleWriter) registry.resolve(byte.class)).write(value.getValue(), stream); } } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumber.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumber.java index e0dc0cc3..c70526e2 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumber.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumber.java @@ -1,6 +1,5 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -10,7 +9,7 @@ @RequiredArgsConstructor(staticName = "of") @Getter @EqualsAndHashCode -public class BlockNumber implements ScaleSelfWritable { +public class BlockNumber { public static final BlockNumber GENESIS = BlockNumber.of(BigInteger.ZERO); private final BigInteger value; diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Reader.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Reader.java index f434a580..9b69af1d 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Reader.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Reader.java @@ -6,19 +6,23 @@ import com.strategyobject.substrateclient.scale.annotation.AutoRegister; import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; import lombok.NonNull; +import lombok.RequiredArgsConstructor; import lombok.val; import java.io.IOException; import java.io.InputStream; @AutoRegister(types = BlockNumber.class) +@RequiredArgsConstructor public class BlockNumberU32Reader implements ScaleReader { + private final @NonNull ScaleReaderRegistry registry; + @SuppressWarnings("unchecked") @Override public BlockNumber read(@NonNull InputStream stream, ScaleReader... readers) throws IOException { Preconditions.checkArgument(readers == null || readers.length == 0); - val u32Reader = (ScaleReader) ScaleReaderRegistry.getInstance().resolve(ScaleType.U32.class); + val u32Reader = (ScaleReader) registry.resolve(ScaleType.U32.class); return BlockNumber.of(u32Reader.read(stream)); } } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Writer.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Writer.java index 0faf830f..01a63156 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Writer.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BlockNumberU32Writer.java @@ -6,18 +6,21 @@ import com.strategyobject.substrateclient.scale.annotation.AutoRegister; import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.NonNull; +import lombok.RequiredArgsConstructor; import java.io.IOException; import java.io.OutputStream; @AutoRegister(types = BlockNumber.class) +@RequiredArgsConstructor public class BlockNumberU32Writer implements ScaleWriter { + private final @NonNull ScaleWriterRegistry registry; + @SuppressWarnings("unchecked") @Override public void write(@NonNull BlockNumber value, @NonNull OutputStream stream, ScaleWriter... writers) throws IOException { Preconditions.checkArgument(writers == null || writers.length == 0); - ((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(ScaleType.U32.class)) - .write(value.getValue().longValue(), stream); + ((ScaleWriter) registry.resolve(ScaleType.U32.class)).write(value.getValue().longValue(), stream); } } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesDecoder.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesDecoder.java index 0f594cc9..bb7b8d17 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesDecoder.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesDecoder.java @@ -1,7 +1,7 @@ package com.strategyobject.substrateclient.rpc.api; import com.strategyobject.substrateclient.common.types.Bytes; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.rpc.DecoderPair; import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; import com.strategyobject.substrateclient.rpc.decoders.AbstractDecoder; diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesEncoder.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesEncoder.java index 3d4a06f2..47a4f091 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesEncoder.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/BytesEncoder.java @@ -2,7 +2,7 @@ import com.google.common.base.Preconditions; import com.strategyobject.substrateclient.common.types.Bytes; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.rpc.EncoderPair; import com.strategyobject.substrateclient.rpc.RpcEncoder; import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; @@ -20,6 +20,6 @@ public class BytesEncoder implements RpcEncoder { public Object encode(Bytes source, EncoderPair... encoders) { Preconditions.checkArgument(encoders == null || encoders.length == 0); - return HexConverter.toHex(source.getData()); + return HexConverter.toHex(source.getBytes()); } } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Call.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Call.java index e2c3dc37..7c8541aa 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Call.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Call.java @@ -1,6 +1,4 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; - -public interface Call extends ScaleSelfWritable { +public interface Call { } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Era.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Era.java index b6db5dce..9697bdd5 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Era.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Era.java @@ -1,6 +1,4 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; - -public interface Era extends ScaleSelfWritable { +public interface Era { } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Extra.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Extra.java index 139858c3..64c450aa 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Extra.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Extra.java @@ -1,6 +1,4 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; - -public interface Extra extends ScaleSelfWritable { +public interface Extra { } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Extrinsic.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Extrinsic.java index 65ca3798..fdb72166 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Extrinsic.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Extrinsic.java @@ -1,13 +1,11 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; import lombok.Getter; import java.util.Optional; @Getter -public class Extrinsic - implements ScaleSelfWritable> { +public class Extrinsic { private final Optional> signature; private final C call; diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/ExtrinsicStatusDecoder.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/ExtrinsicStatusDecoder.java index 2a8472b9..d3ff7b4e 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/ExtrinsicStatusDecoder.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/ExtrinsicStatusDecoder.java @@ -4,17 +4,24 @@ import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; import com.strategyobject.substrateclient.rpc.decoders.AbstractDecoder; import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; import com.strategyobject.substrateclient.transport.RpcObject; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import java.util.HashMap; import java.util.Map; import java.util.Optional; @AutoRegister(types = ExtrinsicStatus.class) +@RequiredArgsConstructor public class ExtrinsicStatusDecoder extends AbstractDecoder { private static final Map STATUS_TO_VALUE = new HashMap<>(); private static final Map> STATUS_TO_CLASS = new HashMap<>(); + private final @NonNull RpcDecoderRegistry decoderRegistry; + private final @NonNull ScaleReaderRegistry scaleReaderRegistry; + static { STATUS_TO_VALUE.put("future", ExtrinsicStatus.Future); STATUS_TO_VALUE.put("ready", ExtrinsicStatus.Ready); @@ -35,14 +42,11 @@ protected ExtrinsicStatus decodeNonNull(RpcObject value, DecoderPair[] decode if (value.isString()) { decoded = Optional.ofNullable(STATUS_TO_VALUE.get(value.asString())); } else if (value.isMap()) { - decoded = (value.asMap()).entrySet().stream() + decoded = (value.asMap()).entrySet() + .stream() .filter(e -> STATUS_TO_CLASS.containsKey(e.getKey())) .findFirst() - .map(e -> - (ExtrinsicStatus) RpcDecoderRegistry.getInstance() - .resolve(STATUS_TO_CLASS.get(e.getKey())) - .decode(value) - ); + .map(e -> (ExtrinsicStatus) decoderRegistry.resolve(STATUS_TO_CLASS.get(e.getKey())).decode(value)); } else { decoded = Optional.empty(); } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/ExtrinsicWriter.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/ExtrinsicWriter.java index c83ff061..9b39473e 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/ExtrinsicWriter.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/ExtrinsicWriter.java @@ -1,23 +1,28 @@ package com.strategyobject.substrateclient.rpc.api; import com.google.common.base.Preconditions; +import com.strategyobject.substrateclient.scale.ScaleDispatch; import com.strategyobject.substrateclient.scale.ScaleType; import com.strategyobject.substrateclient.scale.ScaleWriter; import com.strategyobject.substrateclient.scale.annotation.AutoRegister; import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import com.strategyobject.substrateclient.scale.writers.ByteArrayWriter; import lombok.NonNull; +import lombok.RequiredArgsConstructor; import lombok.val; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.util.Optional; @AutoRegister(types = Extrinsic.class) +@RequiredArgsConstructor public class ExtrinsicWriter implements ScaleWriter> { private static final int VERSION = 4; + private final @NonNull ScaleWriterRegistry registry; + @Override public void write(@NonNull Extrinsic value, @NonNull OutputStream stream, @@ -29,26 +34,26 @@ public void write(@NonNull Extrinsic value, wrapToVec(encodedExtrinsic, stream); } - @SuppressWarnings("unchecked") private void wrapToVec(ByteArrayOutputStream encodedExtrinsic, OutputStream stream) throws IOException { - ((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(ScaleType.CompactInteger.class)) - .write(encodedExtrinsic.size(), stream); - - stream.write(encodedExtrinsic.toByteArray()); + ((ByteArrayWriter) registry.resolve(byte[].class)).write(encodedExtrinsic.toByteArray(), stream); } @SuppressWarnings("unchecked") private void writeExtrinsic(Extrinsic value, ByteArrayOutputStream stream) throws IOException { - val u8Writer = (ScaleWriter) ScaleWriterRegistry.getInstance().resolve(ScaleType.U8.class); - val maybeSignature = value.getSignature(); - if (maybeSignature.isPresent()) { + val u8Writer = (ScaleWriter) registry.resolve(ScaleType.U8.class); + val signature = value.getSignature(); + if (signature.isPresent()) { u8Writer.write(VERSION | 0b1000_0000, stream); - val signature = maybeSignature.get(); - signature.write(stream); + + val dispatcher = registry.resolve(ScaleDispatch.class); + val signaturePayloadWriter = (ScaleWriter>) registry.resolve(SignaturePayload.class); + signaturePayloadWriter + .inject(dispatcher, dispatcher, dispatcher) + .write(signature.get(), stream); } else { u8Writer.write(VERSION & 0b0111_1111, stream); } - value.getCall().write(stream); + ((ScaleWriter) registry.resolve(ScaleDispatch.class)).write(value.getCall(), stream); } } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/FixedBytesWriter.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/FixedBytesWriter.java index 0cc50cf1..5bd02b88 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/FixedBytesWriter.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/FixedBytesWriter.java @@ -30,6 +30,6 @@ public void write(@NonNull FixedBytes value, ScaleWriter... writers) throws IOException { Preconditions.checkArgument(writers == null || writers.length == 0); - Streamer.writeBytes(value.getData(), stream); + Streamer.writeBytes(value.getBytes(), stream); } } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Hash.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Hash.java index 150db0a6..e9c8ed0b 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Hash.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Hash.java @@ -1,7 +1,8 @@ package com.strategyobject.substrateclient.rpc.api; import com.strategyobject.substrateclient.common.types.Bytes; +import lombok.NonNull; public interface Hash extends Bytes { - byte[] getData(); + byte @NonNull [] getBytes(); } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Index.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Index.java index f99a1569..2c48c742 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Index.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Index.java @@ -1,6 +1,5 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; import com.strategyobject.substrateclient.scale.ScaleType; import com.strategyobject.substrateclient.scale.annotation.Scale; import com.strategyobject.substrateclient.scale.annotation.ScaleWriter; @@ -14,7 +13,7 @@ @Getter @EqualsAndHashCode @ScaleWriter -public class Index implements ScaleSelfWritable { +public class Index { public static final Index ZERO = Index.of(BigInteger.ZERO); @Scale(ScaleType.CompactBigInteger.class) diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Metadata.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Metadata.java index 44cc5364..ed9fc2a1 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Metadata.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Metadata.java @@ -1,8 +1,7 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; import com.strategyobject.substrateclient.scale.annotation.ScaleReader; @ScaleReader -public class Metadata implements ScaleSelfWritable { +public class Metadata { } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Signature.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Signature.java index 0caebf4a..8a646db9 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Signature.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/Signature.java @@ -1,7 +1,5 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; - -public interface Signature extends ScaleSelfWritable { +public interface Signature { SignatureKind getKind(); } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignatureKindWriter.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignatureKindWriter.java index 7734cf6b..029b0cca 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignatureKindWriter.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignatureKindWriter.java @@ -5,17 +5,21 @@ import com.strategyobject.substrateclient.scale.annotation.AutoRegister; import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.NonNull; +import lombok.RequiredArgsConstructor; import java.io.IOException; import java.io.OutputStream; @AutoRegister(types = SignatureKind.class) +@RequiredArgsConstructor public class SignatureKindWriter implements ScaleWriter { + private final @NonNull ScaleWriterRegistry registry; + @Override @SuppressWarnings("unchecked") public void write(@NonNull SignatureKind value, @NonNull OutputStream stream, ScaleWriter... writers) throws IOException { Preconditions.checkArgument(writers == null || writers.length == 0); - ((ScaleWriter) ScaleWriterRegistry.getInstance().resolve(byte.class)).write(value.getValue(), stream); + ((ScaleWriter) registry.resolve(byte.class)).write(value.getValue(), stream); } } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignaturePayload.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignaturePayload.java index d3f4ab6b..8e8c8af5 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignaturePayload.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignaturePayload.java @@ -1,6 +1,5 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; import com.strategyobject.substrateclient.scale.annotation.ScaleWriter; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -8,7 +7,7 @@ @RequiredArgsConstructor @Getter @ScaleWriter -public class SignaturePayload implements ScaleSelfWritable> { +public class SignaturePayload { private final A address; private final S signature; private final E extra; diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedExtra.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedExtra.java index 07267f00..634c4d5a 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedExtra.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedExtra.java @@ -3,7 +3,6 @@ import com.strategyobject.substrateclient.scale.ScaleType; import com.strategyobject.substrateclient.scale.annotation.Ignore; import com.strategyobject.substrateclient.scale.annotation.Scale; -import com.strategyobject.substrateclient.scale.annotation.ScaleWriter; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -11,7 +10,6 @@ @RequiredArgsConstructor @Getter -@ScaleWriter public class SignedExtra implements Extra, SignedExtension { @Ignore private final long specVersion; diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedExtraWriter.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedExtraWriter.java new file mode 100644 index 00000000..b2b44a26 --- /dev/null +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedExtraWriter.java @@ -0,0 +1,32 @@ +package com.strategyobject.substrateclient.rpc.api; + +import com.google.common.base.Preconditions; +import com.strategyobject.substrateclient.scale.ScaleDispatch; +import com.strategyobject.substrateclient.scale.ScaleType; +import com.strategyobject.substrateclient.scale.ScaleWriter; +import com.strategyobject.substrateclient.scale.annotation.AutoRegister; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.val; + +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; + +@AutoRegister(types = com.strategyobject.substrateclient.rpc.api.SignedExtra.class) +@RequiredArgsConstructor +public class SignedExtraWriter implements ScaleWriter> { + private final @NonNull ScaleWriterRegistry registry; + + @Override + @SuppressWarnings({"unchecked"}) + public void write(@NonNull SignedExtra value, @NonNull OutputStream stream, ScaleWriter... writers) throws IOException { + Preconditions.checkArgument(writers == null || writers.length == 0); + + val dispatcher = registry.resolve(ScaleDispatch.class); + ((ScaleWriter) dispatcher).write(value.getEra(), stream); + ((ScaleWriter) registry.resolve(Index.class)).write(value.getNonce(), stream); + ((ScaleWriter) registry.resolve(ScaleType.CompactBigInteger.class)).write(value.getTip(), stream); + } +} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedPayload.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedPayload.java index 999da423..8c60d298 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedPayload.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedPayload.java @@ -1,32 +1,11 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.crypto.Signable; import lombok.Getter; -import lombok.NonNull; import lombok.RequiredArgsConstructor; -import lombok.val; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; @RequiredArgsConstructor @Getter -public class SignedPayload - implements Signable { +public class SignedPayload { private final C call; private final E extra; - - @Override - public byte @NonNull [] getBytes() { - val buf = new ByteArrayOutputStream(); - try { - call.write(buf); - extra.write(buf); - extra.getAdditionalExtra().write(buf); - - return buf.toByteArray(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedPayloadWriter.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedPayloadWriter.java new file mode 100644 index 00000000..7c5ea55c --- /dev/null +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/SignedPayloadWriter.java @@ -0,0 +1,30 @@ +package com.strategyobject.substrateclient.rpc.api; + +import com.google.common.base.Preconditions; +import com.strategyobject.substrateclient.scale.ScaleDispatch; +import com.strategyobject.substrateclient.scale.ScaleWriter; +import com.strategyobject.substrateclient.scale.annotation.AutoRegister; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.val; + +import java.io.IOException; +import java.io.OutputStream; + +@RequiredArgsConstructor +@AutoRegister(types = SignedPayload.class) +public class SignedPayloadWriter implements ScaleWriter> { + private final @NonNull ScaleWriterRegistry registry; + + @SuppressWarnings("unchecked") + @Override + public void write(@NonNull SignedPayload value, @NonNull OutputStream stream, ScaleWriter... writers) throws IOException { + Preconditions.checkArgument(writers == null || writers.length == 0); + + val dispatcher = registry.resolve(ScaleDispatch.class); + ((ScaleWriter) dispatcher).write(value.getCall(), stream); + ((ScaleWriter) dispatcher).write(value.getExtra(), stream); + ((ScaleWriter) dispatcher).write(value.getExtra().getAdditionalExtra(), stream); + } +} diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageDataDecoder.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageDataDecoder.java index f70dde6c..15c0c414 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageDataDecoder.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageDataDecoder.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.rpc.DecoderPair; import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; import com.strategyobject.substrateclient.rpc.decoders.AbstractDecoder; diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageKeyDecoder.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageKeyDecoder.java index 5139b4a8..aae8f4b0 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageKeyDecoder.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageKeyDecoder.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.rpc.api; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.rpc.DecoderPair; import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; import com.strategyobject.substrateclient.rpc.decoders.AbstractDecoder; diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageKeyEncoder.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageKeyEncoder.java index 10a1097f..ae05cf67 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageKeyEncoder.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/StorageKeyEncoder.java @@ -1,7 +1,7 @@ package com.strategyobject.substrateclient.rpc.api; import com.google.common.base.Preconditions; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.rpc.EncoderPair; import com.strategyobject.substrateclient.rpc.RpcEncoder; import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256.java index e7becf6a..89429518 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256.java @@ -4,10 +4,9 @@ import com.strategyobject.substrateclient.common.types.Size; import com.strategyobject.substrateclient.rpc.api.BlockHash; import com.strategyobject.substrateclient.rpc.api.Hash; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; import lombok.NonNull; -public class Hash256 extends FixedBytes implements Hash, BlockHash, ScaleSelfWritable { +public class Hash256 extends FixedBytes implements Hash, BlockHash { private Hash256(byte[] data) { super(data, Size.of32); } diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256Decoder.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256Decoder.java index bcbee317..73372f5c 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256Decoder.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/impl/Hash256Decoder.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.rpc.api.impl; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.rpc.DecoderPair; import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; import com.strategyobject.substrateclient.rpc.api.BlockHash; diff --git a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/Author.java b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/Author.java index d977b84f..b0bcd48d 100644 --- a/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/Author.java +++ b/rpc/rpc-api/src/main/java/com/strategyobject/substrateclient/rpc/api/section/Author.java @@ -8,6 +8,7 @@ import com.strategyobject.substrateclient.rpc.api.ExtrinsicStatus; import com.strategyobject.substrateclient.rpc.api.Hash; import com.strategyobject.substrateclient.scale.annotation.Scale; +import com.strategyobject.substrateclient.scale.annotation.ScaleGeneric; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; @@ -38,22 +39,26 @@ public interface Author { CompletableFuture insertKey(String keyType, String secretUri, Bytes publicKey); /** - * Submit an extrinsic to watch. + * Submit hex-encoded extrinsic for inclusion in block. * * @param extrinsic extrinsic to submit - * @param callback callback handler - * @return unsubscribe delegate + * @return hash of extrinsic */ - @RpcSubscription(type = "extrinsicUpdate", subscribeMethod = "submitAndWatchExtrinsic", unsubscribeMethod = "unwatchExtrinsic") - CompletableFuture>> submitAndWatchExtrinsic(@Scale Extrinsic extrinsic, - BiConsumer callback); + @RpcCall("submitExtrinsic") + CompletableFuture submitExtrinsic( + @ScaleGeneric(template = "Extrinsic", types = @Scale(Extrinsic.class)) + Extrinsic extrinsic); /** - * Submit hex-encoded extrinsic for inclusion in block. + * Submit an extrinsic to watch. * * @param extrinsic extrinsic to submit - * @return hash of extrinsic + * @param callback callback handler + * @return unsubscribe delegate */ - @RpcCall("submitExtrinsic") - CompletableFuture submitExtrinsic(@Scale Extrinsic extrinsic); + @RpcSubscription(type = "extrinsicUpdate", subscribeMethod = "submitAndWatchExtrinsic", unsubscribeMethod = "unwatchExtrinsic") + CompletableFuture>> submitAndWatchExtrinsic( + @ScaleGeneric(template = "Extrinsic", types = @Scale(Extrinsic.class)) + Extrinsic extrinsic, + BiConsumer callback); } diff --git a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/AuthorTests.java b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/AuthorTests.java index 3b5c3f0c..93e51191 100644 --- a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/AuthorTests.java +++ b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/AuthorTests.java @@ -1,10 +1,14 @@ package com.strategyobject.substrateclient.rpc.api.section; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.common.types.Size; -import com.strategyobject.substrateclient.common.utils.HexConverter; -import com.strategyobject.substrateclient.crypto.*; -import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; +import com.strategyobject.substrateclient.crypto.Hasher; +import com.strategyobject.substrateclient.crypto.KeyPair; +import com.strategyobject.substrateclient.crypto.KeyRing; +import com.strategyobject.substrateclient.crypto.PublicKey; import com.strategyobject.substrateclient.rpc.api.*; +import com.strategyobject.substrateclient.scale.ScaleUtils; +import com.strategyobject.substrateclient.scale.ScaleWriter; import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; import com.strategyobject.substrateclient.tests.containers.TestSubstrateContainer; import com.strategyobject.substrateclient.transport.ws.WsProvider; @@ -40,7 +44,7 @@ class AuthorTests { @Test void hasKey() throws Exception { try (val wsProvider = connect()) { - val author = RpcGeneratedSectionFactory.create(Author.class, wsProvider); + val author = TestsHelper.createSectionFactory(wsProvider).create(Author.class); val publicKey = PublicKey.fromBytes( HexConverter.toBytes("0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d")); @@ -59,7 +63,7 @@ void hasKey() throws Exception { @Test void insertKey() throws Exception { try (val wsProvider = connect()) { - val author = RpcGeneratedSectionFactory.create(Author.class, wsProvider); + val author = TestsHelper.createSectionFactory(wsProvider).create(Author.class); Assertions.assertDoesNotThrow(() -> author.insertKey("aura", "alice", @@ -72,10 +76,11 @@ void insertKey() throws Exception { @Test void submitExtrinsic() throws Exception { try (val wsProvider = connect()) { - val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + val sectionFactory = TestsHelper.createSectionFactory(wsProvider); + val chain = sectionFactory.create(Chain.class); val genesis = chain.getBlockHash(BlockNumber.GENESIS).get(WAIT_TIMEOUT, TimeUnit.SECONDS); - val author = RpcGeneratedSectionFactory.create(Author.class, wsProvider); + val author = sectionFactory.create(Author.class); Assertions.assertDoesNotThrow(() -> author.submitExtrinsic(createBalanceTransferExtrinsic(genesis, NONCE.getAndIncrement())) .get(WAIT_TIMEOUT, TimeUnit.SECONDS)); } @@ -84,10 +89,12 @@ void submitExtrinsic() throws Exception { @Test void submitAndWatchExtrinsic() throws Exception { try (val wsProvider = connect()) { - val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + val sectionFactory = TestsHelper.createSectionFactory(wsProvider); + + val chain = sectionFactory.create(Chain.class); val genesis = chain.getBlockHash(BlockNumber.GENESIS).get(WAIT_TIMEOUT, TimeUnit.SECONDS); - val author = RpcGeneratedSectionFactory.create(Author.class, wsProvider); + val author = sectionFactory.create(Author.class); val updateCount = new AtomicInteger(0); val status = new AtomicReference(); val unsubscribe = author.submitAndWatchExtrinsic( @@ -110,6 +117,7 @@ void submitAndWatchExtrinsic() throws Exception { } } + private WsProvider connect() throws ExecutionException, InterruptedException, TimeoutException { val wsProvider = WsProvider.builder() .setEndpoint(substrate.getWsAddress()) @@ -120,31 +128,32 @@ private WsProvider connect() throws ExecutionException, InterruptedException, Ti return wsProvider; } + @SuppressWarnings({"unchecked"}) private Extrinsic createBalanceTransferExtrinsic(BlockHash genesis, int nonce) { val specVersion = 264; val txVersion = 2; val moduleIndex = (byte) 6; val callIndex = (byte) 0; val tip = 0; - val call = new BalanceTransfer(moduleIndex, callIndex, AddressId.fromBytes(bobKeyPair().asPublicKey().getData()), BigInteger.valueOf(10)); + val call = new BalanceTransfer(moduleIndex, callIndex, AddressId.fromBytes(bobKeyPair().asPublicKey().getBytes()), BigInteger.valueOf(10)); val extra = new SignedExtra<>(specVersion, txVersion, genesis, genesis, new ImmortalEra(), Index.of(nonce), BigInteger.valueOf(tip)); - val signedPayload = new SignedPayload<>(call, extra); + val writer = (ScaleWriter>>) TestsHelper.SCALE_WRITER_REGISTRY.resolve(SignedPayload.class); + val signedPayload = ScaleUtils.toBytes(new SignedPayload<>(call, extra), writer); val keyRing = KeyRing.fromKeyPair(aliceKeyPair()); val signature = sign(keyRing, signedPayload); return Extrinsic.createSigned( new SignaturePayload<>( - AddressId.fromBytes(aliceKeyPair().asPublicKey().getData()), + AddressId.fromBytes(aliceKeyPair().asPublicKey().getBytes()), signature, extra ), call); } - private Signature sign(KeyRing keyRing, Signable payload) { - var signed = payload.getBytes(); - val signature = signed.length > 256 ? Hasher.blake2(Size.of256, signed) : signed; + private Signature sign(KeyRing keyRing, byte[] payload) { + val signature = payload.length > 256 ? Hasher.blake2(Size.of256, payload) : payload; return Sr25519Signature.from(keyRing.sign(() -> signature)); } diff --git a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/ChainTests.java b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/ChainTests.java index a36acfcb..876d4435 100644 --- a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/ChainTests.java +++ b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/ChainTests.java @@ -1,6 +1,5 @@ package com.strategyobject.substrateclient.rpc.api.section; -import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; import com.strategyobject.substrateclient.rpc.api.BlockHash; import com.strategyobject.substrateclient.rpc.api.BlockNumber; import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; @@ -36,17 +35,17 @@ class ChainTests { @Test void getFinalizedHead() throws Exception { try (val wsProvider = connect()) { - val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + val chain = TestsHelper.createSectionFactory(wsProvider).create(Chain.class); val result = chain.getFinalizedHead().get(WAIT_TIMEOUT, TimeUnit.SECONDS); - assertNotEquals(BigInteger.ZERO, new BigInteger(result.getData())); + assertNotEquals(BigInteger.ZERO, new BigInteger(result.getBytes())); } } @Test void subscribeNewHeads() throws Exception { try (val wsProvider = connect()) { - val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + val chain = TestsHelper.createSectionFactory(wsProvider).create(Chain.class); val blockCount = new AtomicInteger(0); val blockHash = new AtomicReference(null); @@ -63,7 +62,7 @@ void subscribeNewHeads() throws Exception { .atMost(WAIT_TIMEOUT * 2, TimeUnit.SECONDS) .untilAtomic(blockCount, greaterThan(2)); - assertNotEquals(BigInteger.ZERO, new BigInteger(blockHash.get().getData())); + assertNotEquals(BigInteger.ZERO, new BigInteger(blockHash.get().getBytes())); val result = unsubscribeFunc.get().get(WAIT_TIMEOUT, TimeUnit.SECONDS); @@ -74,17 +73,17 @@ void subscribeNewHeads() throws Exception { @Test void getBlockHash() throws Exception { try (val wsProvider = connect()) { - val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + val chain = TestsHelper.createSectionFactory(wsProvider).create(Chain.class); val result = chain.getBlockHash().get(WAIT_TIMEOUT, TimeUnit.SECONDS); - assertNotEquals(BigInteger.ZERO, new BigInteger(result.getData())); + assertNotEquals(BigInteger.ZERO, new BigInteger(result.getBytes())); } } @Test void getBlock() throws Exception { try (val wsProvider = connect()) { - val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + val chain = TestsHelper.createSectionFactory(wsProvider).create(Chain.class); val height = new AtomicInteger(0); chain.subscribeNewHeads((e, header) -> { @@ -100,11 +99,11 @@ void getBlock() throws Exception { val number = height.get(); val blockHash = chain.getBlockHash(BlockNumber.of(number)).get(WAIT_TIMEOUT, TimeUnit.SECONDS); - assertNotEquals(BigInteger.ZERO, new BigInteger(blockHash.getData())); + assertNotEquals(BigInteger.ZERO, new BigInteger(blockHash.getBytes())); val block = chain.getBlock(blockHash).get(WAIT_TIMEOUT, TimeUnit.SECONDS); - assertNotEquals(BigInteger.ZERO, new BigInteger(block.getBlock().getHeader().getParentHash().getData())); + assertNotEquals(BigInteger.ZERO, new BigInteger(block.getBlock().getHeader().getParentHash().getBytes())); assertEquals(number, block.getBlock().getHeader().getNumber().getValue().intValue()); } } @@ -112,7 +111,7 @@ void getBlock() throws Exception { @Test void getCurrentBlock() throws ExecutionException, InterruptedException, TimeoutException { try (val wsProvider = connect()) { - val chain = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + val chain = TestsHelper.createSectionFactory(wsProvider).create(Chain.class); val height = new AtomicInteger(0); chain.subscribeNewHeads((e, header) -> { @@ -127,7 +126,7 @@ void getCurrentBlock() throws ExecutionException, InterruptedException, TimeoutE val block = chain.getBlock().get(WAIT_TIMEOUT, TimeUnit.SECONDS); - assertNotEquals(BigInteger.ZERO, new BigInteger(block.getBlock().getHeader().getParentHash().getData())); + assertNotEquals(BigInteger.ZERO, new BigInteger(block.getBlock().getHeader().getParentHash().getBytes())); assertNotNull(block.getBlock().getHeader().getNumber()); } } diff --git a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/StateTests.java b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/StateTests.java index 3bcad266..330ca7af 100644 --- a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/StateTests.java +++ b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/StateTests.java @@ -1,7 +1,6 @@ package com.strategyobject.substrateclient.rpc.api.section; -import com.strategyobject.substrateclient.common.utils.HexConverter; -import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.rpc.api.BlockNumber; import com.strategyobject.substrateclient.rpc.api.StorageKey; import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; @@ -40,7 +39,7 @@ class StateTests { @Test void getRuntimeVersion() throws Exception { try (val wsProvider = connect()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); assertDoesNotThrow(() -> { state.getRuntimeVersion().get(WAIT_TIMEOUT, TimeUnit.SECONDS); @@ -51,7 +50,7 @@ void getRuntimeVersion() throws Exception { @Test void getMetadata() throws Exception { try (val wsProvider = connect()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); assertDoesNotThrow(() -> { state.getMetadata().get(WAIT_TIMEOUT * 10, TimeUnit.SECONDS); @@ -62,7 +61,7 @@ void getMetadata() throws Exception { @Test void getKeys() throws Exception { try (val wsProvider = connect()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val keys = state.getKeys(storageKey).get(WAIT_TIMEOUT, TimeUnit.SECONDS); @@ -73,7 +72,7 @@ void getKeys() throws Exception { @Test void getStorage() throws Exception { try (val wsProvider = connect()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val storageData = state.getStorage(storageKey).get(WAIT_TIMEOUT, TimeUnit.SECONDS); @@ -85,7 +84,7 @@ void getStorage() throws Exception { @Test void getStorageHandlesNullResponse() throws Exception { try (val wsProvider = connect()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val emptyKey = new byte[32]; val storageData = state.getStorage(StorageKey.valueOf(emptyKey)).get(WAIT_TIMEOUT, TimeUnit.SECONDS); @@ -97,9 +96,9 @@ void getStorageHandlesNullResponse() throws Exception { @Test void getStorageAtBlock() throws Exception { try (val wsProvider = connect()) { - val chainSection = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + val chainSection = TestsHelper.createSectionFactory(wsProvider).create(Chain.class); val blockHash = chainSection.getBlockHash(BlockNumber.GENESIS).get(WAIT_TIMEOUT, TimeUnit.SECONDS); - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val storageData = state.getStorage(storageKey, blockHash).get(WAIT_TIMEOUT, TimeUnit.SECONDS); @@ -111,33 +110,33 @@ void getStorageAtBlock() throws Exception { @Test void getStorageHash() throws Exception { try (val wsProvider = connect()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val hash = state.getStorageHash(storageKey).get(WAIT_TIMEOUT, TimeUnit.SECONDS); assertNotNull(hash); - assertTrue(hash.getData().length > 0); + assertTrue(hash.getBytes().length > 0); } } @Test void getStorageHashAt() throws Exception { try (val wsProvider = connect()) { - val chainSection = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + val chainSection = TestsHelper.createSectionFactory(wsProvider).create(Chain.class); val blockHash = chainSection.getBlockHash(BlockNumber.GENESIS).get(WAIT_TIMEOUT, TimeUnit.SECONDS); - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val hash = state.getStorageHash(storageKey, blockHash).get(WAIT_TIMEOUT, TimeUnit.SECONDS); assertNotNull(hash); - assertTrue(hash.getData().length > 0); + assertTrue(hash.getBytes().length > 0); } } @Test void getStorageSize() throws Exception { try (val wsProvider = connect()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val size = state.getStorageSize(storageKey).get(WAIT_TIMEOUT, TimeUnit.SECONDS); @@ -148,9 +147,9 @@ void getStorageSize() throws Exception { @Test void getStorageSizeAt() throws Exception { try (val wsProvider = connect()) { - val chainSection = RpcGeneratedSectionFactory.create(Chain.class, wsProvider); + val chainSection = TestsHelper.createSectionFactory(wsProvider).create(Chain.class); val blockHash = chainSection.getBlockHash(BlockNumber.GENESIS).get(WAIT_TIMEOUT, TimeUnit.SECONDS); - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val size = state.getStorageSize(storageKey, blockHash).get(WAIT_TIMEOUT, TimeUnit.SECONDS); @@ -161,7 +160,7 @@ void getStorageSizeAt() throws Exception { @Test void queryStorageAt() throws Exception { try (val wsProvider = connect()) { - val state = RpcGeneratedSectionFactory.create(State.class, wsProvider); + val state = TestsHelper.createSectionFactory(wsProvider).create(State.class); val changes = state .queryStorageAt(Collections.singletonList(storageKey)) diff --git a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/SystemTests.java b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/SystemTests.java index 1479871b..1a5d1c9e 100644 --- a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/SystemTests.java +++ b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/SystemTests.java @@ -1,14 +1,12 @@ package com.strategyobject.substrateclient.rpc.api.section; -import com.strategyobject.substrateclient.common.utils.HexConverter; -import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.rpc.api.AccountId; import com.strategyobject.substrateclient.rpc.api.Index; import com.strategyobject.substrateclient.tests.containers.SubstrateVersion; import com.strategyobject.substrateclient.tests.containers.TestSubstrateContainer; import com.strategyobject.substrateclient.transport.ws.WsProvider; import lombok.val; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.testcontainers.containers.Network; import org.testcontainers.junit.jupiter.Container; @@ -16,6 +14,8 @@ import java.util.concurrent.TimeUnit; +import static org.junit.jupiter.api.Assertions.assertEquals; + @Testcontainers class SystemTests { private static final int WAIT_TIMEOUT = 10; @@ -32,13 +32,13 @@ void accountNextIndex() throws Exception { .build()) { wsProvider.connect().get(WAIT_TIMEOUT, TimeUnit.SECONDS); - val system = RpcGeneratedSectionFactory.create(System.class, wsProvider); + val system = TestsHelper.createSectionFactory(wsProvider).create(System.class); val alicePublicKey = HexConverter.toBytes("0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"); val result = system.accountNextIndex(AccountId.fromBytes(alicePublicKey)) .get(WAIT_TIMEOUT, TimeUnit.SECONDS); - Assertions.assertEquals(Index.ZERO, result); + assertEquals(Index.ZERO, result); } } } diff --git a/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/TestsHelper.java b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/TestsHelper.java new file mode 100644 index 00000000..2e4e0032 --- /dev/null +++ b/rpc/rpc-api/src/test/java/com/strategyobject/substrateclient/rpc/api/section/TestsHelper.java @@ -0,0 +1,35 @@ +package com.strategyobject.substrateclient.rpc.api.section; + +import com.strategyobject.substrateclient.rpc.GeneratedRpcSectionFactory; +import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry; +import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import com.strategyobject.substrateclient.transport.ProviderInterface; + +public class TestsHelper { + static final ScaleReaderRegistry SCALE_READER_REGISTRY = new ScaleReaderRegistry() {{ + registerAnnotatedFrom("com.strategyobject.substrateclient"); + }}; + + static final ScaleWriterRegistry SCALE_WRITER_REGISTRY = new ScaleWriterRegistry() {{ + registerAnnotatedFrom("com.strategyobject.substrateclient"); + }}; + + static final RpcEncoderRegistry RPC_ENCODER_REGISTRY = new RpcEncoderRegistry(SCALE_WRITER_REGISTRY) {{ + registerAnnotatedFrom("com.strategyobject.substrateclient"); + }}; + + static final RpcDecoderRegistry RPC_DECODER_REGISTRY = new RpcDecoderRegistry(SCALE_READER_REGISTRY) {{ + registerAnnotatedFrom("com.strategyobject.substrateclient"); + }}; + + static GeneratedRpcSectionFactory createSectionFactory(ProviderInterface provider) { + return new GeneratedRpcSectionFactory( + provider, + RPC_ENCODER_REGISTRY, + SCALE_WRITER_REGISTRY, + RPC_DECODER_REGISTRY, + SCALE_READER_REGISTRY); + } +} diff --git a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/Constants.java b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/Constants.java index bb90a7d7..74a31230 100644 --- a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/Constants.java +++ b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/Constants.java @@ -1,9 +1,9 @@ package com.strategyobject.substrateclient.rpc.codegen; -import com.strategyobject.substrateclient.rpc.RpcSelfEncodable; +import com.strategyobject.substrateclient.rpc.RpcDispatch; public class Constants { - public static final Class RPC_SELF_ENCODABLE = RpcSelfEncodable.class; + public static final Class RPC_DISPATCH = RpcDispatch.class; public static final String AUTO_REGISTER_TYPES_ARG = "types"; public static final String PAIR_FACTORY_METHOD = "of"; diff --git a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/decoder/DecoderCompositor.java b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/decoder/DecoderCompositor.java index dd72aae6..b0e16044 100644 --- a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/decoder/DecoderCompositor.java +++ b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/decoder/DecoderCompositor.java @@ -2,6 +2,7 @@ import com.squareup.javapoet.CodeBlock; import com.strategyobject.substrateclient.common.codegen.ProcessorContext; +import com.strategyobject.substrateclient.common.codegen.TypeNotSupportedException; import com.strategyobject.substrateclient.common.codegen.TypeTraverser; import com.strategyobject.substrateclient.common.types.Array; import com.strategyobject.substrateclient.rpc.DecoderPair; @@ -72,13 +73,21 @@ private CodeBlock getGenericCodeBlock(TypeMirror type, CodeBlock[] subtypes) { var builder = CodeBlock.builder() .add("$T.$L(", DecoderPair.class, PAIR_FACTORY_METHOD) - .add("$T.$L($T.class, ", RpcRegistryHelper.class, RESOLVE_AND_INJECT_METHOD, resolveType); + .add("$T.$L($L, $T.class, ", + RpcRegistryHelper.class, + RESOLVE_AND_INJECT_METHOD, + decoderRegistryVarName, + resolveType); for (var i = 0; i < subtypes.length; i++) { if (i > 0) builder.add(", "); builder.add(subtypes[i]); } - builder.add("), $T.$L($T.class, ", ScaleRegistryHelper.class, RESOLVE_AND_INJECT_METHOD, resolveType); + builder.add("), $T.$L($L, $T.class, ", + ScaleRegistryHelper.class, + RESOLVE_AND_INJECT_METHOD, + scaleRegistryVarName, + resolveType); for (var i = 0; i < subtypes.length; i++) { if (i > 0) builder.add(", "); builder.add(subtypes[i]); @@ -90,6 +99,11 @@ private CodeBlock getGenericCodeBlock(TypeMirror type, CodeBlock[] subtypes) { .add(")").build(); } + @Override + protected CodeBlock whenWildcard(TypeMirror override) { + throw new TypeNotSupportedException("WILDCARD"); + } + @Override protected CodeBlock whenTypeVar(@NonNull TypeVariable type, TypeMirror _override) { return getTypeVarCodeBlock(type); diff --git a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/decoder/RpcDecoderAnnotatedClass.java b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/decoder/RpcDecoderAnnotatedClass.java index d8dd7d8a..a485b75e 100644 --- a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/decoder/RpcDecoderAnnotatedClass.java +++ b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/decoder/RpcDecoderAnnotatedClass.java @@ -1,9 +1,7 @@ package com.strategyobject.substrateclient.rpc.codegen.decoder; import com.squareup.javapoet.*; -import com.strategyobject.substrateclient.common.codegen.JavaPoet; -import com.strategyobject.substrateclient.common.codegen.ProcessingException; -import com.strategyobject.substrateclient.common.codegen.ProcessorContext; +import com.strategyobject.substrateclient.common.codegen.*; import com.strategyobject.substrateclient.rpc.DecoderPair; import com.strategyobject.substrateclient.rpc.RpcDecoder; import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; @@ -69,7 +67,9 @@ public void generateDecoder(@NonNull ProcessorContext context) throws Processing .addMember(AUTO_REGISTER_TYPES_ARG, "{$L.class}", classElement.getQualifiedName().toString()) .build()) .addModifiers(Modifier.PUBLIC) - .addSuperinterface(ParameterizedTypeName.get(ClassName.get(RpcDecoder.class), classWildcardTyped)) + .addSuperinterface(ParameterizedTypeName.get(ClassName.get(RpcDecoder.class), classWildcardTyped)); + + injectDependencies(typeSpecBuilder) .addMethod(generateDecodeMethod(context, classWildcardTyped)); JavaFile.builder( @@ -99,11 +99,30 @@ private MethodSpec generateDecodeMethod(ProcessorContext context, TypeName class return methodSpec.build(); } + private TypeSpec.Builder injectDependencies(TypeSpec.Builder typeSpecBuilder) { + val ctor = MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter(RpcDecoderRegistry.class, DECODER_REGISTRY) + .addParameter(ScaleReaderRegistry.class, SCALE_READER_REGISTRY) + .beginControlFlow("if ($L == null)", DECODER_REGISTRY) + .addStatement("throw new $T(\"$L can't be null.\")", IllegalArgumentException.class, DECODER_REGISTRY) + .endControlFlow() + .addStatement("this.$1L = $1L", DECODER_REGISTRY) + .beginControlFlow("if ($L == null)", SCALE_READER_REGISTRY) + .addStatement("throw new $T(\"$L can't be null.\")", IllegalArgumentException.class, SCALE_READER_REGISTRY) + .endControlFlow() + .addStatement("this.$1L = $1L", SCALE_READER_REGISTRY) + .build(); + + return typeSpecBuilder + .addField(RpcDecoderRegistry.class, DECODER_REGISTRY, Modifier.PRIVATE, Modifier.FINAL) + .addField(ScaleReaderRegistry.class, SCALE_READER_REGISTRY, Modifier.PRIVATE, Modifier.FINAL) + .addMethod(ctor); + } + private void addMethodBody(MethodSpec.Builder methodSpec, ProcessorContext context) throws ProcessingException { val resultType = JavaPoet.setEachGenericParameterAs(classElement, TypeName.OBJECT); methodSpec - .addStatement("$1T $2L = $1T.getInstance()", RpcDecoderRegistry.class, DECODER_REGISTRY) - .addStatement("$1T $2L = $1T.getInstance()", ScaleReaderRegistry.class, SCALE_READER_REGISTRY) .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"); @@ -134,11 +153,11 @@ private void setFields(MethodSpec.Builder methodSpec, ProcessorContext context) SCALE_READER_REGISTRY); for (VariableElement field : fields) { - if (field.getAnnotation(Ignore.class) != null) { + if (AnnotationUtils.isAnnotatedWith(field, Ignore.class)) { continue; } - if (field.getAnnotation(Scale.class) != null || field.getAnnotation(ScaleGeneric.class) != null) { + if (AnnotationUtils.isAnnotatedWithAny(field, Scale.class, ScaleGeneric.class)) { setScaleField(methodSpec, context, field, scaleAnnotationParser, scaleReaderCompositor); } else { setField(methodSpec, field, context, decoderCompositor); diff --git a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/encoder/EncoderCompositor.java b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/encoder/EncoderCompositor.java index e794a1e0..c4cfcf9b 100644 --- a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/encoder/EncoderCompositor.java +++ b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/encoder/EncoderCompositor.java @@ -21,7 +21,6 @@ public class EncoderCompositor extends TypeTraverser { private final ProcessorContext context; private final Map typeVarMap; - private final TypeMirror selfEncodable; private final String encoderAccessor; private final String writerAccessor; private final String writerMethod; @@ -39,7 +38,6 @@ public EncoderCompositor(@NonNull ProcessorContext context, super(CodeBlock.class); this.context = context; this.typeVarMap = typeVarMap; - this.selfEncodable = context.erasure(context.getType(RPC_SELF_ENCODABLE)); this.encoderAccessor = encoderAccessor; this.writerAccessor = writerAccessor; this.writerMethod = writerMethod; @@ -51,11 +49,7 @@ public EncoderCompositor(@NonNull ProcessorContext context, private CodeBlock getNonGenericCodeBlock(TypeMirror type) { return CodeBlock.builder() .add("$T.$L(($T) ", EncoderPair.class, PAIR_FACTORY_METHOD, RpcEncoder.class) - .add("$L.resolve($T.class)", - encoderRegistryVarName, - context.isAssignable(type, selfEncodable) ? - selfEncodable : - type) + .add("$L.resolve($T.class)", encoderRegistryVarName, type) .add(", ($T) ", ScaleWriter.class) .add("$L.resolve($T.class)", scaleRegistryVarName, type) .add(")") @@ -65,41 +59,45 @@ private CodeBlock getNonGenericCodeBlock(TypeMirror type) { private CodeBlock getGenericCodeBlock(TypeMirror type, CodeBlock[] subtypes) { TypeMirror resolveType = context.erasure(type); val builder = CodeBlock.builder() - .add("$T.$L(", EncoderPair.class, PAIR_FACTORY_METHOD); - - if (context.isAssignable(resolveType, selfEncodable)) { - builder.add("($T) registry.resolve($T.class)", selfEncodable, RpcEncoder.class); - } else { - builder.add("$T.$L($T.class, ", RpcRegistryHelper.class, RESOLVE_AND_INJECT_METHOD, resolveType); - for (var i = 0; i < subtypes.length; i++) { - if (i > 0) builder.add(", "); - builder.add(subtypes[i]); - } + .add("$T.$L(", EncoderPair.class, PAIR_FACTORY_METHOD) + .add("$T.$L($L, $T.class, ", + RpcRegistryHelper.class, + RESOLVE_AND_INJECT_METHOD, + encoderRegistryVarName, + resolveType); + + for (var i = 0; i < subtypes.length; i++) { + if (i > 0) builder.add(", "); + builder.add(subtypes[i]); } - builder.add("), $T.$L($T.class, ", ScaleRegistryHelper.class, RESOLVE_AND_INJECT_METHOD, resolveType); + builder.add("), $T.$L($L, $T.class, ", + ScaleRegistryHelper.class, + RESOLVE_AND_INJECT_METHOD, + scaleRegistryVarName, + resolveType); + for (var i = 0; i < subtypes.length; i++) { if (i > 0) builder.add(", "); builder.add(subtypes[i]); builder.add(".$L", writerMethod); } - builder.add(")"); - return builder.add(")").build(); + return builder.add("))").build(); } @Override - protected CodeBlock whenTypeVar(@NonNull TypeVariable type, TypeMirror _override) { - val builder = CodeBlock.builder() - .add("$T.$L(($T) ", EncoderPair.class, PAIR_FACTORY_METHOD, RpcEncoder.class); - - if (context.isAssignable(type, selfEncodable)) { - builder.add("$L.resolve($T.class)", encoderRegistryVarName, selfEncodable); - } else { - builder.add(encoderAccessor, typeVarMap.get(type.toString())); - } + protected CodeBlock whenWildcard(TypeMirror override) { + return CodeBlock.builder() + .add("$L.resolve($T.class)", encoderRegistryVarName, RPC_DISPATCH) + .build(); + } - return builder.add(", ($T) ", ScaleWriter.class) + @Override + protected CodeBlock whenTypeVar(@NonNull TypeVariable type, TypeMirror _override) { + return CodeBlock.builder() + .add("$T.$L(($T) ", EncoderPair.class, PAIR_FACTORY_METHOD, RpcEncoder.class) + .add(encoderAccessor, typeVarMap.get(type.toString())).add(", ($T) ", ScaleWriter.class) .add(writerAccessor, typeVarMap.get(type.toString())) .add(")") .build(); @@ -129,9 +127,4 @@ protected CodeBlock whenArrayPrimitiveType(@NonNull ArrayType type, TypeMirror _ protected CodeBlock whenArrayType(@NonNull ArrayType type, TypeMirror _override, @NonNull CodeBlock subtype) { return getGenericCodeBlock(arrayType, new CodeBlock[]{subtype}); } - - @Override - protected boolean doTraverseArguments(@NonNull DeclaredType type, TypeMirror override) { - return override != null || !context.isAssignable(context.erasure(type), selfEncodable); - } } diff --git a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/encoder/RpcEncoderAnnotatedClass.java b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/encoder/RpcEncoderAnnotatedClass.java index e968ce54..74fcdc74 100644 --- a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/encoder/RpcEncoderAnnotatedClass.java +++ b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/encoder/RpcEncoderAnnotatedClass.java @@ -1,6 +1,7 @@ package com.strategyobject.substrateclient.rpc.codegen.encoder; import com.squareup.javapoet.*; +import com.strategyobject.substrateclient.common.codegen.AnnotationUtils; import com.strategyobject.substrateclient.common.codegen.JavaPoet; import com.strategyobject.substrateclient.common.codegen.ProcessingException; import com.strategyobject.substrateclient.common.codegen.ProcessorContext; @@ -69,7 +70,9 @@ public void generateEncoder(@NonNull ProcessorContext context) throws Processing .addMember(AUTO_REGISTER_TYPES_ARG, "{$L.class}", classElement.getQualifiedName().toString()) .build()) .addModifiers(Modifier.PUBLIC) - .addSuperinterface(ParameterizedTypeName.get(ClassName.get(RpcEncoder.class), classWildcardTyped)) + .addSuperinterface(ParameterizedTypeName.get(ClassName.get(RpcEncoder.class), classWildcardTyped)); + + injectDependencies(typeSpecBuilder) .addMethod(generateEncodeMethod(context, classWildcardTyped)); JavaFile.builder( @@ -78,6 +81,27 @@ public void generateEncoder(@NonNull ProcessorContext context) throws Processing ).build().writeTo(context.getFiler()); } + private TypeSpec.Builder injectDependencies(TypeSpec.Builder typeSpecBuilder) { + val ctor = MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter(RpcEncoderRegistry.class, ENCODER_REGISTRY) + .addParameter(ScaleWriterRegistry.class, SCALE_WRITER_REGISTRY) + .beginControlFlow("if ($L == null)", ENCODER_REGISTRY) + .addStatement("throw new $T(\"$L can't be null.\")", IllegalArgumentException.class, ENCODER_REGISTRY) + .endControlFlow() + .addStatement("this.$1L = $1L", ENCODER_REGISTRY) + .beginControlFlow("if ($L == null)", SCALE_WRITER_REGISTRY) + .addStatement("throw new $T(\"$L can't be null.\")", IllegalArgumentException.class, SCALE_WRITER_REGISTRY) + .endControlFlow() + .addStatement("this.$1L = $1L", SCALE_WRITER_REGISTRY) + .build(); + + return typeSpecBuilder + .addField(RpcEncoderRegistry.class, ENCODER_REGISTRY, Modifier.PRIVATE, Modifier.FINAL) + .addField(ScaleWriterRegistry.class, SCALE_WRITER_REGISTRY, Modifier.PRIVATE, Modifier.FINAL) + .addMethod(ctor); + } + private MethodSpec generateEncodeMethod(ProcessorContext context, TypeName classWildcardTyped) throws ProcessingException { val methodSpec = MethodSpec.methodBuilder(ENCODE_METHOD_NAME) .addAnnotation(Override.class) @@ -93,7 +117,7 @@ private MethodSpec generateEncodeMethod(ProcessorContext context, TypeName class .varargs(true); shortcutIfNull(methodSpec); - addValidationRules(methodSpec, context); + addValidationRules(methodSpec); addMethodBody(methodSpec, context); return methodSpec.build(); @@ -101,8 +125,6 @@ private MethodSpec generateEncodeMethod(ProcessorContext context, TypeName class private void addMethodBody(MethodSpec.Builder methodSpec, ProcessorContext context) throws ProcessingException { methodSpec - .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) .beginControlFlow("try"); @@ -130,11 +152,11 @@ private void setFields(MethodSpec.Builder methodSpec, ProcessorContext context) SCALE_WRITER_REGISTRY); for (VariableElement field : fields) { - if (field.getAnnotation(Ignore.class) != null) { + if (AnnotationUtils.isAnnotatedWith(field, Ignore.class)) { continue; } - if (field.getAnnotation(Scale.class) != null || field.getAnnotation(ScaleGeneric.class) != null) { + if (AnnotationUtils.isAnnotatedWithAny(field, Scale.class, ScaleGeneric.class)) { setScaleField(methodSpec, field, scaleAnnotationParser, scaleWriterCompositor); } else { setField(methodSpec, field, context, encoderCompositor); @@ -210,9 +232,9 @@ private void setScaleField(MethodSpec.Builder methodSpec, } - private void addValidationRules(MethodSpec.Builder methodSpec, ProcessorContext context) { + private void addValidationRules(MethodSpec.Builder methodSpec) { val classTypeParametersSize = classElement.getTypeParameters().size(); - if (classTypeParametersSize == 0 || context.isAssignable(classElement.asType(), context.erasure(context.getType(RPC_SELF_ENCODABLE)))) { + if (classTypeParametersSize == 0) { methodSpec.addStatement("if ($1L != null && $1L.length > 0) throw new $2T()", ENCODERS_ARG, IllegalArgumentException.class); } else { methodSpec diff --git a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcAnnotatedInterface.java b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcAnnotatedInterface.java index e6fe6d5f..f33d83ac 100644 --- a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcAnnotatedInterface.java +++ b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcAnnotatedInterface.java @@ -8,16 +8,21 @@ import com.strategyobject.substrateclient.common.codegen.ProcessingException; import com.strategyobject.substrateclient.common.codegen.ProcessorContext; import com.strategyobject.substrateclient.rpc.annotation.RpcInterface; +import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry; +import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import com.strategyobject.substrateclient.transport.ProviderInterface; import lombok.NonNull; import lombok.val; -import lombok.var; +import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import java.io.IOException; +import static com.strategyobject.substrateclient.rpc.codegen.Constants.*; import static com.strategyobject.substrateclient.rpc.codegen.sections.Constants.CLASS_NAME_TEMPLATE; import static com.strategyobject.substrateclient.rpc.codegen.sections.Constants.PROVIDER_INTERFACE; @@ -59,9 +64,13 @@ public void generateClass(@NonNull ProcessorContext context) .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addSuperinterface(TypeName.get(interfaceElement.asType())) .addField(ProviderInterface.class, PROVIDER_INTERFACE) + .addField(RpcEncoderRegistry.class, ENCODER_REGISTRY) + .addField(ScaleWriterRegistry.class, SCALE_WRITER_REGISTRY) + .addField(RpcDecoderRegistry.class, DECODER_REGISTRY) + .addField(ScaleReaderRegistry.class, SCALE_READER_REGISTRY) .addMethod(createConstructor()); - for (var method : interfaceElement.getEnclosedElements()) { + for (Element method : interfaceElement.getEnclosedElements()) { methodProcessor.process(section, (ExecutableElement) method, typeSpecBuilder, context); } @@ -69,13 +78,31 @@ public void generateClass(@NonNull ProcessorContext context) } private MethodSpec createConstructor() { - return MethodSpec.constructorBuilder() + val methodSpec = MethodSpec.constructorBuilder() .addModifiers(Modifier.PUBLIC) .addParameter(ProviderInterface.class, PROVIDER_INTERFACE) - .beginControlFlow("if ($L == null)", PROVIDER_INTERFACE) - .addStatement("throw new $T(\"$L can't be null.\")", IllegalArgumentException.class, PROVIDER_INTERFACE) - .endControlFlow() - .addStatement("this.$1L = $1L", PROVIDER_INTERFACE) - .build(); + .addParameter(RpcEncoderRegistry.class, ENCODER_REGISTRY) + .addParameter(ScaleWriterRegistry.class, SCALE_WRITER_REGISTRY) + .addParameter(RpcDecoderRegistry.class, DECODER_REGISTRY) + .addParameter(ScaleReaderRegistry.class, SCALE_READER_REGISTRY); + + assignParameters(methodSpec, + PROVIDER_INTERFACE, + ENCODER_REGISTRY, + SCALE_WRITER_REGISTRY, + DECODER_REGISTRY, + SCALE_READER_REGISTRY); + + return methodSpec.build(); + } + + private void assignParameters(MethodSpec.Builder methodSpec, String... parameters) { + for (val parameter : parameters) { + methodSpec + .beginControlFlow("if ($L == null)", parameter) + .addStatement("throw new $T(\"$L can't be null.\")", IllegalArgumentException.class, parameter) + .endControlFlow() + .addStatement("this.$1L = $1L", parameter); + } } } diff --git a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcCallProcessor.java b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcCallProcessor.java index 5491fbca..4abae637 100644 --- a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcCallProcessor.java +++ b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcCallProcessor.java @@ -70,11 +70,6 @@ protected void callProviderInterface(MethodSpec.Builder methodSpecBuilder, methodSpecBuilder.addStatement(code.build()); } - @Override - protected boolean useDecodeRegistries(ExecutableElement method, ProcessorContext context) { - return !isReturnVoid(method, context); - } - @Override protected boolean shouldBePassedToProvider(ExecutableElement method, VariableElement param, ProcessorContext context) { return true; diff --git a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcInterfaceMethodValidatingProcessor.java b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcInterfaceMethodValidatingProcessor.java index b74b441d..e5062502 100644 --- a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcInterfaceMethodValidatingProcessor.java +++ b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcInterfaceMethodValidatingProcessor.java @@ -1,6 +1,7 @@ package com.strategyobject.substrateclient.rpc.codegen.sections; import com.squareup.javapoet.TypeSpec; +import com.strategyobject.substrateclient.common.codegen.AnnotationUtils; import com.strategyobject.substrateclient.common.codegen.ProcessingException; import com.strategyobject.substrateclient.common.codegen.ProcessorContext; import com.strategyobject.substrateclient.rpc.annotation.RpcCall; @@ -29,12 +30,10 @@ void process(@NonNull String section, private void ensureMethodIsNotAbstractOrProperlyAnnotated(Element method) throws ProcessingException { val modifiers = method.getModifiers(); - val requiresMethod = method.getAnnotation(RpcCall.class) != null; - val requiresSubscription = method.getAnnotation(RpcSubscription.class) != null; // Ensure method is not abstract or annotated with `RpcMethod` or `RpcSubscription` if (!(modifiers.contains(Modifier.STATIC) || modifiers.contains(Modifier.DEFAULT)) - && !(requiresMethod || requiresSubscription)) { + && !AnnotationUtils.isAnnotatedWithAny(method, RpcCall.class, RpcSubscription.class)) { throw new ProcessingException( interfaceElement, "Method `%s` can't be constructed because it doesn't have `@%s` or `@%s` annotation.", @@ -44,7 +43,7 @@ private void ensureMethodIsNotAbstractOrProperlyAnnotated(Element method) throws } // Ensure method doesn't have ambiguous annotations - if (requiresMethod && requiresSubscription) { + if (AnnotationUtils.isAnnotatedWithAll(method, RpcCall.class, RpcSubscription.class)) { throw new ProcessingException( interfaceElement, "Method `%s` can't be constructed because it has ambiguous annotations. Only one of `@%s` and `@%s` should be chosen.", diff --git a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcMethodProcessor.java b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcMethodProcessor.java index 347d3aee..4f465a55 100644 --- a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcMethodProcessor.java +++ b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcMethodProcessor.java @@ -4,13 +4,12 @@ import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; +import com.strategyobject.substrateclient.common.codegen.AnnotationUtils; import com.strategyobject.substrateclient.common.codegen.ProcessingException; import com.strategyobject.substrateclient.common.codegen.ProcessorContext; import com.strategyobject.substrateclient.rpc.RpcDecoder; import com.strategyobject.substrateclient.rpc.codegen.decoder.DecoderCompositor; import com.strategyobject.substrateclient.rpc.codegen.encoder.EncoderCompositor; -import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry; -import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry; import com.strategyobject.substrateclient.scale.ScaleReader; import com.strategyobject.substrateclient.scale.ScaleUtils; import com.strategyobject.substrateclient.scale.ScaleWriter; @@ -19,8 +18,6 @@ import com.strategyobject.substrateclient.scale.codegen.ScaleAnnotationParser; import com.strategyobject.substrateclient.scale.codegen.reader.ReaderCompositor; import com.strategyobject.substrateclient.scale.codegen.writer.WriterCompositor; -import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; -import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.NonNull; import lombok.val; @@ -93,10 +90,6 @@ private void sendRequest(MethodSpec.Builder methodSpecBuilder, A annotation, ScaleAnnotationParser scaleAnnotationParser, ProcessorContext context) { - if (useDecodeRegistries(method, context)) { - declareDecoderAndReaderRegistries(methodSpecBuilder); - } - callProviderInterface(methodSpecBuilder, method, section, @@ -117,7 +110,7 @@ private CodeBlock getDecodeCodeBlock(AnnotatedConstruct annotated, String arg, ScaleAnnotationParser scaleAnnotationParser, ProcessorContext context) { - return annotated.getAnnotation(Scale.class) != null || annotated.getAnnotation(ScaleGeneric.class) != null ? + return AnnotationUtils.isAnnotatedWithAny(annotated, Scale.class, ScaleGeneric.class) ? getScaleReadCodeBlock(annotated, resultType, arg, scaleAnnotationParser, context) : getRpcDecodeCodeBlock(resultType, arg, context); } @@ -163,8 +156,6 @@ private CodeBlock getScaleReadCodeBlock(AnnotatedConstruct annotated, .build(); } - protected abstract boolean useDecodeRegistries(ExecutableElement method, ProcessorContext context); - private void processParameters(MethodSpec.Builder methodSpecBuilder, ExecutableElement method, ScaleAnnotationParser scaleAnnotationParser, @@ -175,8 +166,7 @@ private void processParameters(MethodSpec.Builder methodSpecBuilder, return; } - val writerCompositor = WriterCompositor.disallowOpenGeneric(context, - SCALE_WRITER_REGISTRY); + val writerCompositor = WriterCompositor.disallowOpenGeneric(context, SCALE_WRITER_REGISTRY); val encoderCompositor = new EncoderCompositor( context, EMPTY_TYPE_VAR_MAP, @@ -186,14 +176,11 @@ private void processParameters(MethodSpec.Builder methodSpecBuilder, ENCODER_REGISTRY, SCALE_WRITER_REGISTRY); - methodSpecBuilder - .addStatement("$1T<$2T> $3L = new $4T<$2T>()", - List.class, - Object.class, - PARAMS_VAR, - ArrayList.class) - .addStatement("$1T $2L = $1T.getInstance()", RpcEncoderRegistry.class, ENCODER_REGISTRY) - .addStatement("$1T $2L = $1T.getInstance()", ScaleWriterRegistry.class, SCALE_WRITER_REGISTRY); + methodSpecBuilder.addStatement("$1T<$2T> $3L = new $4T<$2T>()", + List.class, + Object.class, + PARAMS_VAR, + ArrayList.class); for (val param : method.getParameters()) { try { @@ -218,7 +205,7 @@ private void processParameter(MethodSpec.Builder methodSpecBuilder, if (shouldBePassedToProvider(method, param, context)) { CodeBlock encodeBlock; - if (param.getAnnotation(Scale.class) != null || param.getAnnotation(ScaleGeneric.class) != null) { + if (AnnotationUtils.isAnnotatedWithAny(param, Scale.class, ScaleGeneric.class)) { encodeBlock = getScaleWriteCodeBlock(param, scaleAnnotationParser, writerCompositor); } else { encodeBlock = getRpcEncodeCodeBlock(param, encoderCompositor); @@ -262,12 +249,6 @@ private CodeBlock getRpcEncodeCodeBlock(VariableElement param, protected abstract void onParametersVisited(ExecutableElement method) throws ProcessingException; - private void declareDecoderAndReaderRegistries(MethodSpec.Builder methodSpecBuilder) { - methodSpecBuilder - .addStatement("$1T $2L = $1T.getInstance()", RpcDecoderRegistry.class, DECODER_REGISTRY) - .addStatement("$1T $2L = $1T.getInstance()", ScaleReaderRegistry.class, SCALE_READER_REGISTRY); - } - protected abstract void ensureMethodHasAppropriateReturnType(ExecutableElement method, TypeMirror returnType, ProcessorContext context) throws ProcessingException; protected abstract void ensureAnnotationIsFilled(ExecutableElement method, A annotation) throws ProcessingException; diff --git a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcSubscriptionProcessor.java b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcSubscriptionProcessor.java index e65ca641..0fb17ff4 100644 --- a/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcSubscriptionProcessor.java +++ b/rpc/rpc-codegen/src/main/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcSubscriptionProcessor.java @@ -93,11 +93,6 @@ protected void callProviderInterface(MethodSpec.Builder methodSpecBuilder, .build()); } - @Override - protected boolean useDecodeRegistries(ExecutableElement method, ProcessorContext context) { - return !isCallbackResultVoid(context); - } - @Override protected boolean shouldBePassedToProvider(ExecutableElement method, VariableElement param, ProcessorContext context) throws ProcessingException { val paramType = param.asType(); diff --git a/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/decoder/RpcDecoderProcessorTests.java b/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/decoder/RpcDecoderProcessorTests.java index d3dea00a..08e96ee5 100644 --- a/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/decoder/RpcDecoderProcessorTests.java +++ b/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/decoder/RpcDecoderProcessorTests.java @@ -2,9 +2,10 @@ import com.google.gson.Gson; import com.google.testing.compile.JavaFileObjects; -import com.strategyobject.substrateclient.rpc.codegen.substitutes.TestDecodable; import com.strategyobject.substrateclient.rpc.DecoderPair; +import com.strategyobject.substrateclient.rpc.codegen.substitutes.TestDecodable; import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; import com.strategyobject.substrateclient.transport.RpcObject; import lombok.val; import org.junit.jupiter.api.Test; @@ -56,7 +57,9 @@ void compiles() { @Test void compilesAndDecodes() { // TODO move this test out of the project - val registry = RpcDecoderRegistry.getInstance(); + val registry = new RpcDecoderRegistry(new ScaleReaderRegistry()); + registry.registerAnnotatedFrom("com.strategyobject.substrateclient.rpc.codegen.substitutes"); + val decoder = registry.resolve(TestDecodable.class) .inject(DecoderPair.of(registry.resolve(String.class), null)); diff --git a/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/encoder/RpcEncoderProcessorTests.java b/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/encoder/RpcEncoderProcessorTests.java index 8a40c187..83be1af3 100644 --- a/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/encoder/RpcEncoderProcessorTests.java +++ b/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/encoder/RpcEncoderProcessorTests.java @@ -2,10 +2,11 @@ import com.google.gson.Gson; import com.google.testing.compile.JavaFileObjects; -import com.strategyobject.substrateclient.rpc.codegen.substitutes.TestEncodable; import com.strategyobject.substrateclient.rpc.EncoderPair; import com.strategyobject.substrateclient.rpc.RpcEncoder; +import com.strategyobject.substrateclient.rpc.codegen.substitutes.TestEncodable; import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.val; import org.junit.jupiter.api.Test; @@ -60,7 +61,9 @@ void compiles() { @Test @SuppressWarnings("unchecked") void compilesAndDecodes() { // TODO move this test out of the project - val registry = RpcEncoderRegistry.getInstance(); + val registry = new RpcEncoderRegistry(new ScaleWriterRegistry()); + registry.registerAnnotatedFrom("com.strategyobject.substrateclient.rpc.codegen.substitutes"); + val encoder = (RpcEncoder>) registry.resolve(TestEncodable.class) .inject( EncoderPair.of( diff --git a/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcInterfaceProcessorTest.java b/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcInterfaceProcessorTest.java index 6bfb8867..ad40337e 100644 --- a/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcInterfaceProcessorTest.java +++ b/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcInterfaceProcessorTest.java @@ -127,5 +127,9 @@ void compilesTestSection() { .compile(clazz); assertThat(compilation).succeeded(); + assertThat(compilation) + .generatedSourceFile("com.strategyobject.substrateclient.rpc.sections.TestSectionImpl") + .contentsAsUtf8String() + .contains("scaleWriterRegistry.resolve(TestDispatch.class))"); } } diff --git a/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcSectionFactoryTest.java b/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcSectionFactoryTest.java index 5d1645ee..e1d07f16 100644 --- a/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcSectionFactoryTest.java +++ b/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/sections/RpcSectionFactoryTest.java @@ -1,7 +1,11 @@ package com.strategyobject.substrateclient.rpc.codegen.sections; -import com.strategyobject.substrateclient.rpc.RpcGeneratedSectionFactory; +import com.strategyobject.substrateclient.rpc.GeneratedRpcSectionFactory; import com.strategyobject.substrateclient.rpc.codegen.substitutes.TestSection; +import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry; +import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import com.strategyobject.substrateclient.transport.ProviderInterface; import com.strategyobject.substrateclient.transport.RpcBoolean; import com.strategyobject.substrateclient.transport.RpcObject; @@ -22,12 +26,19 @@ class RpcSectionFactoryTest { @Test void createsRpcSectionAndCallsMethod() throws ExecutionException, InterruptedException { val expected = true; + val sendFuture = CompletableFuture.completedFuture((RpcObject) new RpcBoolean(expected)); val provider = mock(ProviderInterface.class); when(provider.send(anyString(), anyList())) .thenReturn(sendFuture); - val rpcSection = RpcGeneratedSectionFactory.create(TestSection.class, provider); + val rpcGeneratedSectionFactory = new GeneratedRpcSectionFactory( + provider, + new RpcEncoderRegistry(new ScaleWriterRegistry()), + new ScaleWriterRegistry(), + new RpcDecoderRegistry(new ScaleReaderRegistry()), + new ScaleReaderRegistry()); + val rpcSection = rpcGeneratedSectionFactory.create(TestSection.class); val actual = rpcSection.doNothing("some").get(); diff --git a/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/substitutes/TestDispatch.java b/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/substitutes/TestDispatch.java new file mode 100644 index 00000000..faffe6dc --- /dev/null +++ b/rpc/rpc-codegen/src/test/java/com/strategyobject/substrateclient/rpc/codegen/substitutes/TestDispatch.java @@ -0,0 +1,7 @@ +package com.strategyobject.substrateclient.rpc.codegen.substitutes; + +import com.strategyobject.substrateclient.scale.annotation.ScaleWriter; + +@ScaleWriter +public class TestDispatch { +} diff --git a/rpc/rpc-codegen/src/test/resources/TestSection.java b/rpc/rpc-codegen/src/test/resources/TestSection.java index 54f5e290..456c7d0d 100644 --- a/rpc/rpc-codegen/src/test/resources/TestSection.java +++ b/rpc/rpc-codegen/src/test/resources/TestSection.java @@ -3,6 +3,9 @@ import com.strategyobject.substrateclient.rpc.annotation.RpcCall; import com.strategyobject.substrateclient.rpc.annotation.RpcInterface; import com.strategyobject.substrateclient.rpc.annotation.RpcSubscription; +import com.strategyobject.substrateclient.rpc.codegen.substitutes.TestDispatch; +import com.strategyobject.substrateclient.scale.annotation.Scale; +import com.strategyobject.substrateclient.scale.annotation.ScaleGeneric; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; @@ -11,7 +14,9 @@ @RpcInterface("empty") public interface TestSection { @RpcCall("doNothing") - CompletableFuture doNothing(boolean a); + CompletableFuture doNothing( + @ScaleGeneric(template = "TestDispatch", types = @Scale(TestDispatch.class)) + TestDispatch a); @RpcSubscription(type = "nothing", subscribeMethod = "subscribeNothing", unsubscribeMethod = "unsubscribeNothing") CompletableFuture>> subscribeNothing(boolean a, BiConsumer b); diff --git a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/GeneratedRpcSectionFactory.java b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/GeneratedRpcSectionFactory.java new file mode 100644 index 00000000..ccb8c7cd --- /dev/null +++ b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/GeneratedRpcSectionFactory.java @@ -0,0 +1,59 @@ +package com.strategyobject.substrateclient.rpc; + +import com.strategyobject.substrateclient.rpc.annotation.RpcInterface; +import com.strategyobject.substrateclient.rpc.registries.RpcDecoderRegistry; +import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import com.strategyobject.substrateclient.transport.ProviderInterface; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.val; + +@RequiredArgsConstructor +public class GeneratedRpcSectionFactory implements RpcSectionFactory, AutoCloseable { + private static final String CLASS_NAME_TEMPLATE = "%sImpl"; + + private final ProviderInterface provider; + private final RpcEncoderRegistry rpcEncoderRegistry; + private final ScaleWriterRegistry scaleWriterRegistry; + private final RpcDecoderRegistry rpcDecoderRegistry; + private final ScaleReaderRegistry scaleReaderRegistry; + + @Override + public T create(@NonNull Class interfaceClass) { + if (interfaceClass.getDeclaredAnnotationsByType(RpcInterface.class).length == 0) { + throw new IllegalArgumentException( + String.format("`%s` can't be constructed because isn't annotated with `@%s`.", + interfaceClass.getSimpleName(), + RpcInterface.class.getSimpleName())); + } + + Class clazz; + try { + clazz = Class.forName(String.format(CLASS_NAME_TEMPLATE, interfaceClass.getCanonicalName())); + val ctor = clazz.getConstructor( + ProviderInterface.class, + RpcEncoderRegistry.class, + ScaleWriterRegistry.class, + RpcDecoderRegistry.class, + ScaleReaderRegistry.class); + + return interfaceClass.cast( + ctor.newInstance(provider, + rpcEncoderRegistry, + scaleWriterRegistry, + rpcDecoderRegistry, + scaleReaderRegistry)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + @Override + public void close() throws Exception { + if (provider instanceof AutoCloseable) { + ((AutoCloseable) provider).close(); + } + } +} diff --git a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcDispatch.java b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcDispatch.java new file mode 100644 index 00000000..be66b687 --- /dev/null +++ b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcDispatch.java @@ -0,0 +1,4 @@ +package com.strategyobject.substrateclient.rpc; + +public interface RpcDispatch { +} diff --git a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcGeneratedSectionFactory.java b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcGeneratedSectionFactory.java deleted file mode 100644 index 60e95560..00000000 --- a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcGeneratedSectionFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.strategyobject.substrateclient.rpc; - -import com.strategyobject.substrateclient.rpc.annotation.RpcInterface; -import com.strategyobject.substrateclient.transport.ProviderInterface; -import lombok.NonNull; -import lombok.val; - -public class RpcGeneratedSectionFactory { - private static final String CLASS_NAME_TEMPLATE = "%sImpl"; - - private RpcGeneratedSectionFactory() { - } - - public static T create(@NonNull Class interfaceClass, - @NonNull ProviderInterface provider) { - if (interfaceClass.getDeclaredAnnotationsByType(RpcInterface.class).length == 0) { - throw new IllegalArgumentException( - String.format("`%s` can't be constructed because isn't annotated with `@%s`.", - interfaceClass.getSimpleName(), - RpcInterface.class.getSimpleName())); - } - - Class clazz; - try { - clazz = Class.forName(String.format(CLASS_NAME_TEMPLATE, interfaceClass.getCanonicalName())); - val ctor = clazz.getConstructor(ProviderInterface.class); - - return interfaceClass.cast(ctor.newInstance(provider)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } -} diff --git a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcRegistryHelper.java b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcRegistryHelper.java index 5d627cfd..23d28860 100644 --- a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcRegistryHelper.java +++ b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcRegistryHelper.java @@ -9,8 +9,10 @@ private RpcRegistryHelper() { } @SuppressWarnings("unchecked") - public static RpcDecoder resolveAndInjectOrNull(Class clazz, DecoderPair... dependencies) { - val target = (RpcDecoder) RpcDecoderRegistry.getInstance().resolve(clazz); + public static RpcDecoder resolveAndInjectOrNull(RpcDecoderRegistry registry, + Class clazz, + DecoderPair... dependencies) { + val target = (RpcDecoder) registry.resolve(clazz); if (target == null) { return null; @@ -20,8 +22,10 @@ public static RpcDecoder resolveAndInjectOrNull(Class clazz, DecoderPa } @SuppressWarnings("unchecked") - public static RpcEncoder resolveAndInjectOrNull(Class clazz, EncoderPair... dependencies) { - val target = (RpcEncoder) RpcEncoderRegistry.getInstance().resolve(clazz); + public static RpcEncoder resolveAndInjectOrNull(RpcEncoderRegistry registry, + Class clazz, + EncoderPair... dependencies) { + val target = (RpcEncoder) registry.resolve(clazz); if (target == null) { return null; diff --git a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcSectionFactory.java b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcSectionFactory.java new file mode 100644 index 00000000..8324d293 --- /dev/null +++ b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcSectionFactory.java @@ -0,0 +1,7 @@ +package com.strategyobject.substrateclient.rpc; + +import lombok.NonNull; + +public interface RpcSectionFactory { + T create(@NonNull Class interfaceClass); +} diff --git a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcSelfEncodable.java b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcSelfEncodable.java deleted file mode 100644 index 067d1d65..00000000 --- a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/RpcSelfEncodable.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.strategyobject.substrateclient.rpc; - -import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry; - -public interface RpcSelfEncodable> { - @SuppressWarnings("unchecked") - default Object encode(T source) { - return ((RpcSelfEncodable) RpcEncoderRegistry.getInstance() - .resolve(this.getClass())) - .encode(source); - } -} diff --git a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/encoders/DispatchingEncoder.java b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/encoders/DispatchingEncoder.java new file mode 100644 index 00000000..99c3b372 --- /dev/null +++ b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/encoders/DispatchingEncoder.java @@ -0,0 +1,20 @@ +package com.strategyobject.substrateclient.rpc.encoders; + +import com.strategyobject.substrateclient.rpc.EncoderPair; +import com.strategyobject.substrateclient.rpc.RpcEncoder; +import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.val; + +@RequiredArgsConstructor +public class DispatchingEncoder implements RpcEncoder { + private final @NonNull RpcEncoderRegistry registry; + + @SuppressWarnings("unchecked") + @Override + public Object encode(@NonNull T source, EncoderPair... encoders) { + val encoder = (RpcEncoder) registry.resolve(source.getClass()); + return encoder.encode(source, encoders); + } +} diff --git a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/registries/RpcDecoderRegistry.java b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/registries/RpcDecoderRegistry.java index 5c2c37aa..ec2674eb 100644 --- a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/registries/RpcDecoderRegistry.java +++ b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/registries/RpcDecoderRegistry.java @@ -1,29 +1,33 @@ package com.strategyobject.substrateclient.rpc.registries; +import com.strategyobject.substrateclient.common.reflection.ClassUtils; import com.strategyobject.substrateclient.common.reflection.Scanner; import com.strategyobject.substrateclient.common.types.Array; +import com.strategyobject.substrateclient.common.types.AutoRegistry; import com.strategyobject.substrateclient.common.types.Unit; import com.strategyobject.substrateclient.rpc.RpcDecoder; import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; import com.strategyobject.substrateclient.rpc.decoders.*; +import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -public final class RpcDecoderRegistry { - private static final Logger logger = LoggerFactory.getLogger(RpcDecoderRegistry.class); - private static final String ROOT_PREFIX = "com.strategyobject.substrateclient"; - private static volatile RpcDecoderRegistry instance; +@Slf4j +public class RpcDecoderRegistry implements AutoRegistry { + private final ScaleReaderRegistry scaleReaderRegistry; + private final Map, RpcDecoder> decoders; - private RpcDecoderRegistry() { - decoders = new ConcurrentHashMap<>(128); + public RpcDecoderRegistry(ScaleReaderRegistry scaleReaderRegistry) { + this.scaleReaderRegistry = scaleReaderRegistry; + decoders = new ConcurrentHashMap<>(128); register(new ListDecoder(), List.class); register(new MapDecoder(), Map.class); register(new VoidDecoder(), Void.class, void.class); @@ -37,20 +41,6 @@ private RpcDecoderRegistry() { register(new ShortDecoder(), Short.class, short.class); register(new StringDecoder(), String.class); register(new ArrayDecoder(), Array.class); - - registerAnnotatedFrom(ROOT_PREFIX); - } - - public static RpcDecoderRegistry getInstance() { - if (instance == null) { - synchronized (RpcDecoderRegistry.class) { - if (instance == null) { - instance = new RpcDecoderRegistry(); - } - } - } - - return instance; } public void registerAnnotatedFrom(String... prefixes) { @@ -63,12 +53,20 @@ public void registerAnnotatedFrom(String... prefixes) { try { val types = autoRegister.types(); - logger.info("Auto register decoder {} for types: {}", decoder, types); + log.info("Auto register decoder {} for types: {}", decoder, types); + + RpcDecoder rpcDecoder; + if (ClassUtils.hasDefaultConstructor(decoder)) { + rpcDecoder = decoder.newInstance(); + } else { + val ctor = decoder.getConstructor(RpcDecoderRegistry.class, ScaleReaderRegistry.class); + rpcDecoder = ctor.newInstance(this, scaleReaderRegistry); + } - final RpcDecoder instance = decoder.newInstance(); - register(instance, types); - } catch (InstantiationException | IllegalAccessException e) { - logger.error("Auto registration error", e); + register(rpcDecoder, types); + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | + InvocationTargetException e) { + log.error("Auto registration error", e); } }); } diff --git a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/registries/RpcEncoderRegistry.java b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/registries/RpcEncoderRegistry.java index 4279ad3e..b70701f1 100644 --- a/rpc/src/main/java/com/strategyobject/substrateclient/rpc/registries/RpcEncoderRegistry.java +++ b/rpc/src/main/java/com/strategyobject/substrateclient/rpc/registries/RpcEncoderRegistry.java @@ -1,29 +1,34 @@ package com.strategyobject.substrateclient.rpc.registries; +import com.strategyobject.substrateclient.common.reflection.ClassUtils; import com.strategyobject.substrateclient.common.reflection.Scanner; import com.strategyobject.substrateclient.common.types.Array; +import com.strategyobject.substrateclient.common.types.AutoRegistry; import com.strategyobject.substrateclient.common.types.Unit; +import com.strategyobject.substrateclient.rpc.RpcDispatch; import com.strategyobject.substrateclient.rpc.RpcEncoder; import com.strategyobject.substrateclient.rpc.annotation.AutoRegister; import com.strategyobject.substrateclient.rpc.encoders.*; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -public final class RpcEncoderRegistry { - private static final Logger logger = LoggerFactory.getLogger(RpcEncoderRegistry.class); - private static final String ROOT_PREFIX = "com.strategyobject.substrateclient"; - private static volatile RpcEncoderRegistry instance; +@Slf4j +public class RpcEncoderRegistry implements AutoRegistry { + private final ScaleWriterRegistry scaleWriterRegistry; + private final Map, RpcEncoder> encoders; - private RpcEncoderRegistry() { - encoders = new ConcurrentHashMap<>(128); + public RpcEncoderRegistry(@NonNull ScaleWriterRegistry scaleWriterRegistry) { + this.scaleWriterRegistry = scaleWriterRegistry; + encoders = new ConcurrentHashMap<>(128); register(new PlainEncoder<>(), Void.class, void.class, String.class, Boolean.class, boolean.class, Byte.class, byte.class, Double.class, double.class, Float.class, float.class, Integer.class, int.class, Long.class, @@ -32,20 +37,7 @@ private RpcEncoderRegistry() { register(new ListEncoder(), List.class); register(new MapEncoder(), Map.class); register(new ArrayEncoder(), Array.class); - - registerAnnotatedFrom(ROOT_PREFIX); - } - - public static RpcEncoderRegistry getInstance() { - if (instance == null) { - synchronized (RpcEncoderRegistry.class) { - if (instance == null) { - instance = new RpcEncoderRegistry(); - } - } - } - - return instance; + register(new DispatchingEncoder<>(this), RpcDispatch.class); } public void registerAnnotatedFrom(String... prefixes) { @@ -58,12 +50,20 @@ public void registerAnnotatedFrom(String... prefixes) { try { val types = autoRegister.types(); - logger.info("Auto register encoder {} for types: {}", encoder, types); + log.info("Auto register encoder {} for types: {}", encoder, types); + + RpcEncoder rpcEncoder; + if (ClassUtils.hasDefaultConstructor(encoder)) { + rpcEncoder = encoder.newInstance(); + } else { + val ctor = encoder.getConstructor(RpcEncoderRegistry.class, ScaleWriterRegistry.class); + rpcEncoder = ctor.newInstance(this, scaleWriterRegistry); + } - final RpcEncoder instance = encoder.newInstance(); - register(instance, types); - } catch (InstantiationException | IllegalAccessException e) { - logger.error("Auto registration error", e); + register(rpcEncoder, types); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | + NoSuchMethodException e) { + log.error("Auto registration error", e); } }); } diff --git a/rpc/src/test/java/com/strategyobject/substrateclient/rpc/encoders/DispatchingEncoderTest.java b/rpc/src/test/java/com/strategyobject/substrateclient/rpc/encoders/DispatchingEncoderTest.java new file mode 100644 index 00000000..4b319a7c --- /dev/null +++ b/rpc/src/test/java/com/strategyobject/substrateclient/rpc/encoders/DispatchingEncoderTest.java @@ -0,0 +1,27 @@ +package com.strategyobject.substrateclient.rpc.encoders; + +import com.strategyobject.substrateclient.rpc.RpcDispatch; +import com.strategyobject.substrateclient.rpc.RpcEncoder; +import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry; +import com.strategyobject.substrateclient.rpc.substitutes.TestDispatch; +import com.strategyobject.substrateclient.rpc.substitutes.TestDispatchEncoder; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import lombok.val; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class DispatchingEncoderTest { + private final RpcEncoderRegistry registry = new RpcEncoderRegistry(new ScaleWriterRegistry()) {{ + register(new TestDispatchEncoder(this), TestDispatch.class); + }}; + + @SuppressWarnings("unchecked") + @Test + void encode() { + val encoder = (RpcEncoder) registry.resolve(RpcDispatch.class); + val actual = encoder.encode(new TestDispatch("test")); + + assertEquals("test", actual); + } +} \ No newline at end of file diff --git a/rpc/src/test/java/com/strategyobject/substrateclient/rpc/substitutes/TestDispatch.java b/rpc/src/test/java/com/strategyobject/substrateclient/rpc/substitutes/TestDispatch.java new file mode 100644 index 00000000..ac288e58 --- /dev/null +++ b/rpc/src/test/java/com/strategyobject/substrateclient/rpc/substitutes/TestDispatch.java @@ -0,0 +1,10 @@ +package com.strategyobject.substrateclient.rpc.substitutes; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class TestDispatch { + private final String value; +} diff --git a/rpc/src/test/java/com/strategyobject/substrateclient/rpc/substitutes/TestDispatchEncoder.java b/rpc/src/test/java/com/strategyobject/substrateclient/rpc/substitutes/TestDispatchEncoder.java new file mode 100644 index 00000000..9e2f476a --- /dev/null +++ b/rpc/src/test/java/com/strategyobject/substrateclient/rpc/substitutes/TestDispatchEncoder.java @@ -0,0 +1,19 @@ +package com.strategyobject.substrateclient.rpc.substitutes; + +import com.strategyobject.substrateclient.rpc.EncoderPair; +import com.strategyobject.substrateclient.rpc.RpcEncoder; +import com.strategyobject.substrateclient.rpc.registries.RpcEncoderRegistry; +import lombok.RequiredArgsConstructor; +import lombok.val; + +@RequiredArgsConstructor +public class TestDispatchEncoder implements RpcEncoder { + private final RpcEncoderRegistry rpcEncoderRegistry; + + @SuppressWarnings("unchecked") + @Override + public Object encode(TestDispatch source, EncoderPair... encoders) { + val encoder = (RpcEncoder) rpcEncoderRegistry.resolve(String.class); + return encoder.encode(source.getValue()); + } +} diff --git a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/ScaleAnnotationParser.java b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/ScaleAnnotationParser.java index 93beac0e..a4eccffe 100644 --- a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/ScaleAnnotationParser.java +++ b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/ScaleAnnotationParser.java @@ -5,7 +5,7 @@ import com.strategyobject.substrateclient.common.codegen.ProcessorContext; import com.strategyobject.substrateclient.common.codegen.TypeTraverser; import com.strategyobject.substrateclient.common.codegen.TypeUtils; -import com.strategyobject.substrateclient.common.utils.StringUtils; +import com.strategyobject.substrateclient.common.strings.StringUtils; import com.strategyobject.substrateclient.scale.annotation.Scale; import com.strategyobject.substrateclient.scale.annotation.ScaleGeneric; import lombok.NonNull; @@ -23,6 +23,8 @@ import static com.strategyobject.substrateclient.scale.codegen.ScaleProcessorHelper.SCALE_ANNOTATIONS_DEFAULT; public class ScaleAnnotationParser { + private static final String VALUE = "value"; + private static final String TEMPLATE = "template"; private final ProcessorContext context; public ScaleAnnotationParser(@NonNull ProcessorContext context) { @@ -30,14 +32,14 @@ public ScaleAnnotationParser(@NonNull ProcessorContext context) { } public TypeTraverser.TypeTreeNode parse(@NonNull AnnotatedConstruct annotated) { - val scaleType = AnnotationUtils.getValueFromAnnotation(annotated, Scale.class, "value"); + val scaleType = AnnotationUtils.getValueFromAnnotation(annotated, Scale.class, VALUE); if (scaleType != null) { return new TypeTraverser.TypeTreeNode(scaleType); } val scaleGeneric = AnnotationUtils.getAnnotationMirror(annotated, ScaleGeneric.class); if (scaleGeneric != null) { - val template = AnnotationUtils.getValueFromAnnotation(scaleGeneric, "template"); + val template = AnnotationUtils.getValueFromAnnotation(scaleGeneric, TEMPLATE); val typesMap = getTypesMap(scaleGeneric); return parseTemplate(template, typesMap); } @@ -47,13 +49,13 @@ public TypeTraverser.TypeTreeNode parse(@NonNull AnnotatedConstruct annotated) { public TypeTraverser.TypeTreeNode parse(AnnotationMirror annotation) { if (context.isSameType(annotation.getAnnotationType(), context.getType(Scale.class))) { - val scaleType = AnnotationUtils.getValueFromAnnotation(annotation, "value"); + val scaleType = AnnotationUtils.getValueFromAnnotation(annotation, VALUE); return new TypeTraverser.TypeTreeNode(scaleType); } if (context.isSameType(annotation.getAnnotationType(), context.getType(ScaleGeneric.class))) { - val template = AnnotationUtils.getValueFromAnnotation(annotation, "template"); + val template = AnnotationUtils.getValueFromAnnotation(annotation, TEMPLATE); val typesMap = getTypesMap(annotation); return parseTemplate(template, typesMap); @@ -64,8 +66,11 @@ public TypeTraverser.TypeTreeNode parse(AnnotationMirror annotation) { private TypeTraverser.TypeTreeNode parseTemplate(String template, Map typesMap) { val indexes = StringUtils.allIndexesOfAny(template, "<,>"); - if (indexes.size() == 0 || indexes.get(0) == 0) { - throw new IllegalArgumentException("Wrong template"); + if (indexes.size() == 0) { + return new TypeTraverser.TypeTreeNode(getMappedType(typesMap, template.trim())); + } + if (indexes.get(0) == 0) { + throw new IllegalArgumentException("Template cannot begin with a special character"); } val firstIndex = indexes.get(0); @@ -101,7 +106,7 @@ private TypeTraverser.TypeTreeNode parseTemplate(String template, Map getTypesMap(AnnotationMirror scaleGeneric) { val annotations = AnnotationUtils.>getValueFromAnnotation(scaleGeneric, "types"); val result = new HashMap(Objects.requireNonNull(annotations).size()); for (val annotation : annotations) { - var type = AnnotationUtils.getValueFromAnnotation(annotation, "value"); + var type = AnnotationUtils.getValueFromAnnotation(annotation, VALUE); var name = AnnotationUtils.getValueFromAnnotation(annotation, "name"); validateScaleAnnotationIsNotEmpty(name, type); diff --git a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/ScaleProcessorHelper.java b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/ScaleProcessorHelper.java index 67d2a589..20a75c63 100644 --- a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/ScaleProcessorHelper.java +++ b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/ScaleProcessorHelper.java @@ -1,10 +1,10 @@ package com.strategyobject.substrateclient.scale.codegen; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; +import com.strategyobject.substrateclient.scale.ScaleDispatch; import com.strategyobject.substrateclient.scale.annotation.Default; public class ScaleProcessorHelper { - public static final Class SCALE_SELF_WRITABLE = ScaleSelfWritable.class; + public static final Class SCALE_DISPATCH = ScaleDispatch.class; public static final Class SCALE_ANNOTATIONS_DEFAULT = Default.class; private static final String READER_NAME_TEMPLATE = "%sReader"; private static final String WRITER_NAME_TEMPLATE = "%sWriter"; diff --git a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/reader/ReaderCompositor.java b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/reader/ReaderCompositor.java index 7755970d..6710f5ef 100644 --- a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/reader/ReaderCompositor.java +++ b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/reader/ReaderCompositor.java @@ -3,6 +3,7 @@ import com.google.common.base.Strings; import com.squareup.javapoet.CodeBlock; import com.strategyobject.substrateclient.common.codegen.ProcessorContext; +import com.strategyobject.substrateclient.common.codegen.TypeNotSupportedException; import com.strategyobject.substrateclient.common.codegen.TypeTraverser; import com.strategyobject.substrateclient.common.types.Array; import lombok.NonNull; @@ -83,6 +84,11 @@ private CodeBlock getGenericCodeBlock(TypeMirror type, TypeMirror override, Code } + @Override + protected CodeBlock whenWildcard(TypeMirror override) { + throw new TypeNotSupportedException("WILDCARD"); + } + @Override protected CodeBlock whenTypeVar(@NonNull TypeVariable type, TypeMirror _override) { return getTypeVarCodeBlock(type); diff --git a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/reader/ScaleReaderAnnotatedClass.java b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/reader/ScaleReaderAnnotatedClass.java index 6b0a4d31..196c964e 100644 --- a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/reader/ScaleReaderAnnotatedClass.java +++ b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/reader/ScaleReaderAnnotatedClass.java @@ -1,9 +1,7 @@ package com.strategyobject.substrateclient.scale.codegen.reader; import com.squareup.javapoet.*; -import com.strategyobject.substrateclient.common.codegen.JavaPoet; -import com.strategyobject.substrateclient.common.codegen.ProcessingException; -import com.strategyobject.substrateclient.common.codegen.ProcessorContext; +import com.strategyobject.substrateclient.common.codegen.*; import com.strategyobject.substrateclient.scale.ScaleReader; import com.strategyobject.substrateclient.scale.annotation.AutoRegister; import com.strategyobject.substrateclient.scale.annotation.Ignore; @@ -54,7 +52,9 @@ public void generateReader(@NonNull ProcessorContext context) throws IOException .addMember("types", "{$L.class}", classElement.getQualifiedName().toString()) .build()) .addModifiers(Modifier.PUBLIC) - .addSuperinterface(ParameterizedTypeName.get(ClassName.get(ScaleReader.class), classWildcardTyped)) + .addSuperinterface(ParameterizedTypeName.get(ClassName.get(ScaleReader.class), classWildcardTyped)); + + injectDependencies(typeSpecBuilder) .addMethod(generateReadMethod(classWildcardTyped, context)); JavaFile.builder( @@ -63,6 +63,21 @@ public void generateReader(@NonNull ProcessorContext context) throws IOException ).build().writeTo(context.getFiler()); } + private TypeSpec.Builder injectDependencies(TypeSpec.Builder typeSpecBuilder) { + val ctor = MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter(ScaleReaderRegistry.class, REGISTRY) + .beginControlFlow("if ($L == null)", REGISTRY) + .addStatement("throw new $T(\"$L can't be null.\")", IllegalArgumentException.class, REGISTRY) + .endControlFlow() + .addStatement("this.$1L = $1L", REGISTRY) + .build(); + + return typeSpecBuilder + .addField(ScaleReaderRegistry.class, REGISTRY, Modifier.PRIVATE, Modifier.FINAL) + .addMethod(ctor); + } + private MethodSpec generateReadMethod(TypeName classWildcardTyped, ProcessorContext context) throws ProcessingException { val methodSpec = MethodSpec.methodBuilder("read") @@ -104,7 +119,6 @@ private void addMethodBody(MethodSpec.Builder methodSpec, ProcessorContext context) throws ProcessingException { val resultType = JavaPoet.setEachGenericParameterAs(classElement, TypeName.OBJECT); methodSpec - .addStatement("$1T $2L = $1T.getInstance()", ScaleReaderRegistry.class, REGISTRY) .addStatement("$1T result = new $1T()", resultType) .beginControlFlow("try"); @@ -116,7 +130,7 @@ private void addMethodBody(MethodSpec.Builder methodSpec, for (Element element : classElement.getEnclosedElements()) { if (element instanceof VariableElement) { val field = (VariableElement) element; - if (field.getAnnotation(Ignore.class) == null && !field.getModifiers().contains(Modifier.STATIC)) { + if (!AnnotationUtils.isAnnotatedWith(field, Ignore.class) && !field.getModifiers().contains(Modifier.STATIC)) { setField(methodSpec, field, context.getTypeUtils(), scaleAnnotationParser, compositor); } } diff --git a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterAnnotatedClass.java b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterAnnotatedClass.java index 7481e891..159aea4c 100644 --- a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterAnnotatedClass.java +++ b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterAnnotatedClass.java @@ -1,6 +1,7 @@ package com.strategyobject.substrateclient.scale.codegen.writer; import com.squareup.javapoet.*; +import com.strategyobject.substrateclient.common.codegen.AnnotationUtils; import com.strategyobject.substrateclient.common.codegen.JavaPoet; import com.strategyobject.substrateclient.common.codegen.ProcessingException; import com.strategyobject.substrateclient.common.codegen.ProcessorContext; @@ -26,7 +27,6 @@ import static com.strategyobject.substrateclient.common.codegen.AnnotationUtils.suppressWarnings; import static com.strategyobject.substrateclient.common.codegen.TypeUtils.getGetterName; -import static com.strategyobject.substrateclient.scale.codegen.ScaleProcessorHelper.SCALE_SELF_WRITABLE; import static java.util.stream.Collectors.toMap; public class ScaleWriterAnnotatedClass { @@ -53,7 +53,9 @@ public void generateWriter(@NonNull ProcessorContext context) throws IOException .addMember("types", "{$L.class}", classElement.getQualifiedName().toString()) .build()) .addModifiers(Modifier.PUBLIC) - .addSuperinterface(ParameterizedTypeName.get(ClassName.get(ScaleWriter.class), classWildcardTyped)) + .addSuperinterface(ParameterizedTypeName.get(ClassName.get(ScaleWriter.class), classWildcardTyped)); + + injectDependencies(typeSpecBuilder) .addMethod(generateWriteMethod(classWildcardTyped, context)); JavaFile.builder( @@ -62,6 +64,21 @@ public void generateWriter(@NonNull ProcessorContext context) throws IOException ).build().writeTo(context.getFiler()); } + private TypeSpec.Builder injectDependencies(TypeSpec.Builder typeSpecBuilder) { + val ctor = MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter(ScaleWriterRegistry.class, REGISTRY) + .beginControlFlow("if ($L == null)", REGISTRY) + .addStatement("throw new $T(\"$L can't be null.\")", IllegalArgumentException.class, REGISTRY) + .endControlFlow() + .addStatement("this.$1L = $1L", REGISTRY) + .build(); + + return typeSpecBuilder + .addField(ScaleWriterRegistry.class, REGISTRY, Modifier.PRIVATE, Modifier.FINAL) + .addMethod(ctor); + } + private MethodSpec generateWriteMethod(TypeName classWildcardTyped, ProcessorContext context) throws ProcessingException { val methodSpec = MethodSpec.methodBuilder("write") @@ -75,22 +92,21 @@ private MethodSpec generateWriteMethod(TypeName classWildcardTyped, ParameterizedTypeName.get( ClassName.get(ScaleWriter.class), WildcardTypeName.subtypeOf(Object.class))), - "writers") + WRITERS_ARG) .varargs(true) .addException(IOException.class); - addValidationRules(methodSpec, context); + addValidationRules(methodSpec); addMethodBody(methodSpec, context); return methodSpec.build(); } - private void addValidationRules(MethodSpec.Builder methodSpec, - ProcessorContext context) { + private void addValidationRules(MethodSpec.Builder methodSpec) { methodSpec.addStatement("if (stream == null) throw new IllegalArgumentException(\"stream is null\")"); methodSpec.addStatement("if (value == null) throw new IllegalArgumentException(\"value is null\")"); val classTypeParametersSize = classElement.getTypeParameters().size(); - if (classTypeParametersSize == 0 || context.isAssignable(classElement.asType(), context.erasure(context.getType(SCALE_SELF_WRITABLE)))) { + if (classTypeParametersSize == 0) { methodSpec.addStatement("if (writers != null && writers.length > 0) throw new IllegalArgumentException()"); } else { methodSpec @@ -105,7 +121,6 @@ private void addValidationRules(MethodSpec.Builder methodSpec, private void addMethodBody(MethodSpec.Builder methodSpec, ProcessorContext context) throws ProcessingException { methodSpec - .addStatement("$1T registry = $1T.getInstance()", ScaleWriterRegistry.class) .beginControlFlow("try"); val scaleAnnotationParser = new ScaleAnnotationParser(context); @@ -116,7 +131,7 @@ private void addMethodBody(MethodSpec.Builder methodSpec, for (Element element : classElement.getEnclosedElements()) { if (element instanceof VariableElement) { val field = (VariableElement) element; - if (field.getAnnotation(Ignore.class) == null && !field.getModifiers().contains(Modifier.STATIC)) { + if (!AnnotationUtils.isAnnotatedWith(field, Ignore.class) && !field.getModifiers().contains(Modifier.STATIC)) { setField(methodSpec, field, scaleAnnotationParser, compositor); } } diff --git a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterProcessor.java b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterProcessor.java index a79ed054..1ad15214 100644 --- a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterProcessor.java +++ b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterProcessor.java @@ -14,8 +14,6 @@ import java.io.IOException; import java.util.Set; -import static com.strategyobject.substrateclient.scale.codegen.ScaleProcessorHelper.SCALE_SELF_WRITABLE; - @SupportedAnnotationTypes("com.strategyobject.substrateclient.scale.annotation.ScaleWriter") @SupportedSourceVersion(SourceVersion.RELEASE_8) @AutoService(Processor.class) @@ -48,14 +46,6 @@ public boolean process(Set annotations, RoundEnvironment } val typeElement = (TypeElement) annotatedElement; - if (!validateScaleSelfWritable(typeElement)) { - context.error( - typeElement, - "Classes implementing `%1$s` and annotated with `@%2$s` have to be either non generic or all its parameters have to implement `%1$s`", - SCALE_SELF_WRITABLE.getCanonicalName(), - ScaleWriter.class.getSimpleName()); - } - try { new ScaleWriterAnnotatedClass(typeElement).generateWriter(context); } catch (ProcessingException e) { @@ -69,15 +59,4 @@ public boolean process(Set annotations, RoundEnvironment return true; } - - private boolean validateScaleSelfWritable(TypeElement typeElement) { - val selfWritable = context.erasure(context.getType(SCALE_SELF_WRITABLE)); - if (!context.isAssignable(typeElement.asType(), selfWritable)) { - return true; - } - - val typeParameters = typeElement.getTypeParameters(); - return typeParameters.size() == 0 || - typeParameters.stream().allMatch(x -> context.isAssignable(x.asType(), selfWritable)); - } } diff --git a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/WriterCompositor.java b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/WriterCompositor.java index 7023542c..76e69d7d 100644 --- a/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/WriterCompositor.java +++ b/scale/scale-codegen/src/main/java/com/strategyobject/substrateclient/scale/codegen/writer/WriterCompositor.java @@ -10,17 +10,15 @@ import javax.lang.model.type.*; import java.util.Map; -import static com.strategyobject.substrateclient.scale.codegen.ScaleProcessorHelper.SCALE_SELF_WRITABLE; +import static com.strategyobject.substrateclient.scale.codegen.ScaleProcessorHelper.SCALE_DISPATCH; public class WriterCompositor extends TypeTraverser { private final ProcessorContext context; private final Map typeVarMap; - private final TypeMirror selfWritable; private final String writerAccessor; private final String registryVarName; private final TypeMirror arrayType; - private WriterCompositor(ProcessorContext context, Map typeVarMap, String writerAccessor, @@ -29,7 +27,6 @@ private WriterCompositor(ProcessorContext context, this.context = context; this.typeVarMap = typeVarMap; - this.selfWritable = context.erasure(context.getType(SCALE_SELF_WRITABLE)); this.writerAccessor = writerAccessor; this.registryVarName = registryVarName; this.arrayType = context.erasure(context.getType(Array.class)); @@ -49,13 +46,7 @@ public static WriterCompositor disallowOpenGeneric(@NonNull ProcessorContext con private CodeBlock getNonGenericCodeBlock(TypeMirror type, TypeMirror override) { return CodeBlock.builder() - .add("$L.resolve($T.class)", - registryVarName, - override != null ? - override : - context.isAssignable(type, selfWritable) ? - selfWritable : - type) + .add("$L.resolve($T.class)", registryVarName, override != null ? override : type) .build(); } @@ -71,10 +62,6 @@ private CodeBlock getGenericCodeBlock(TypeMirror type, TypeMirror override, Code resolveType = override; } else { resolveType = context.erasure(type); - - if (context.isAssignable(resolveType, selfWritable)) { - return CodeBlock.builder().add("$L.resolve($T.class)", registryVarName, selfWritable).build(); - } } var builder = CodeBlock.builder().add("$L.resolve($T.class).inject(", registryVarName, resolveType); @@ -86,15 +73,18 @@ private CodeBlock getGenericCodeBlock(TypeMirror type, TypeMirror override, Code return builder.add(")").build(); } + @Override + protected CodeBlock whenWildcard(TypeMirror override) { + return CodeBlock.builder() + .add("$L.resolve($T.class)", registryVarName, SCALE_DISPATCH) + .build(); + } + @Override protected CodeBlock whenTypeVar(@NonNull TypeVariable type, TypeMirror _override) { - return context.isAssignable(type, selfWritable) ? - CodeBlock.builder() - .add("$L.resolve($T.class)", registryVarName, selfWritable) - .build() : - CodeBlock.builder() - .add(writerAccessor, typeVarMap.get(type.toString())) - .build(); + return CodeBlock.builder() + .add(writerAccessor, typeVarMap.get(type.toString())) + .build(); } @Override @@ -111,7 +101,7 @@ protected CodeBlock whenNonGenericType(@NonNull DeclaredType type, TypeMirror ov protected CodeBlock whenGenericType(@NonNull DeclaredType type, TypeMirror override, @NonNull CodeBlock[] subtypes) { TypeMirror resolveType; if (override != null) { - if (context.isNonGeneric(override)) { + if (subtypes.length == 0) { return CodeBlock.builder() .add("$L.resolve($T.class)", registryVarName, override) .build(); @@ -120,10 +110,6 @@ protected CodeBlock whenGenericType(@NonNull DeclaredType type, TypeMirror overr resolveType = override; } else { resolveType = context.erasure(type); - - if (context.isAssignable(resolveType, selfWritable)) { - return CodeBlock.builder().add("$L.resolve($T.class)", registryVarName, selfWritable).build(); - } } var builder = CodeBlock.builder().add("$L.resolve($T.class).inject(", registryVarName, resolveType); @@ -144,9 +130,4 @@ protected CodeBlock whenArrayPrimitiveType(@NonNull ArrayType type, TypeMirror o protected CodeBlock whenArrayType(@NonNull ArrayType type, TypeMirror override, @NonNull CodeBlock subtype) { return getGenericCodeBlock(arrayType, override, new CodeBlock[]{subtype}); } - - @Override - protected boolean doTraverseArguments(@NonNull DeclaredType type, TypeMirror override) { - return override != null || !context.isAssignable(context.erasure(type), selfWritable); - } } diff --git a/scale/scale-codegen/src/test/java/com/strategyobject/substrateclient/scale/codegen/reader/ScaleReaderProcessorTest.java b/scale/scale-codegen/src/test/java/com/strategyobject/substrateclient/scale/codegen/reader/ScaleReaderProcessorTest.java index 4e98a868..e5d95b82 100644 --- a/scale/scale-codegen/src/test/java/com/strategyobject/substrateclient/scale/codegen/reader/ScaleReaderProcessorTest.java +++ b/scale/scale-codegen/src/test/java/com/strategyobject/substrateclient/scale/codegen/reader/ScaleReaderProcessorTest.java @@ -18,7 +18,7 @@ void failsWhenWrongTemplate() { assertThat(compilation).failed(); assertThat(compilation) - .hadErrorContaining("Wrong template"); + .hadErrorContaining("brackets"); } @Test diff --git a/scale/scale-codegen/src/test/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterProcessorTest.java b/scale/scale-codegen/src/test/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterProcessorTest.java index 013d5508..7a4b2fb9 100644 --- a/scale/scale-codegen/src/test/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterProcessorTest.java +++ b/scale/scale-codegen/src/test/java/com/strategyobject/substrateclient/scale/codegen/writer/ScaleWriterProcessorTest.java @@ -18,42 +18,7 @@ void failsWhenWrongTemplate() { assertThat(compilation).failed(); assertThat(compilation) - .hadErrorContaining("Wrong template"); - } - - @Test - void failsWhenMissesScaleSelfWritable() { - val nameless = JavaFileObjects.forResource("MissesScaleSelfWritable.java"); - - val compilation = javac() - .withProcessors(new ScaleWriterProcessor()) - .compile(nameless); - - assertThat(compilation).failed(); - assertThat(compilation) - .hadErrorContaining("ScaleSelfWritable"); - } - - @Test - void compilesNonGenericScaleSelfWritable() { - val clazz = JavaFileObjects.forResource("NonGenericScaleSelfWritable.java"); - - val compilation = javac() - .withProcessors(new ScaleWriterProcessor()) - .compile(clazz); - - assertThat(compilation).succeeded(); - } - - @Test - void compilesGenericScaleSelfWritable() { - val clazz = JavaFileObjects.forResource("GenericScaleSelfWritable.java"); - - val compilation = javac() - .withProcessors(new ScaleWriterProcessor()) - .compile(clazz); - - assertThat(compilation).succeeded(); + .hadErrorContaining("brackets"); } @Test diff --git a/scale/scale-codegen/src/test/resources/GenericScaleSelfWritable.java b/scale/scale-codegen/src/test/resources/GenericScaleSelfWritable.java deleted file mode 100644 index 8c11b3e2..00000000 --- a/scale/scale-codegen/src/test/resources/GenericScaleSelfWritable.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.strategyobject.substrateclient.scale; - -import com.strategyobject.substrateclient.scale.annotation.Scale; -import com.strategyobject.substrateclient.scale.annotation.ScaleWriter; - -@ScaleWriter -public class GenericScaleSelfWritable< - T1 extends ScaleSelfWritable, - T2 extends ScaleSelfWritable, - T3 extends ScaleSelfWritable> implements ScaleSelfWritable> { - - @Scale - private T1 testGeneric1; - - @Scale - private T2 testGeneric2; - - @Scale - private T3 testGeneric3; - - public T1 getTestGeneric1() { - return testGeneric1; - } - - public void setTestGeneric1(T1 testGeneric1) { - this.testGeneric1 = testGeneric1; - } - - public T2 getTestGeneric2() { - return testGeneric2; - } - - public void setTestGeneric2(T2 testGeneric2) { - this.testGeneric2 = testGeneric2; - } - - public T3 getTestGeneric3() { - return testGeneric3; - } - - public void setTestGeneric3(T3 testGeneric3) { - this.testGeneric3 = testGeneric3; - } -} diff --git a/scale/scale-codegen/src/test/resources/MissesScaleSelfWritable.java b/scale/scale-codegen/src/test/resources/MissesScaleSelfWritable.java deleted file mode 100644 index 9343f83d..00000000 --- a/scale/scale-codegen/src/test/resources/MissesScaleSelfWritable.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.strategyobject.substrateclient.scale; - -import com.strategyobject.substrateclient.scale.annotation.ScaleWriter; - -@ScaleWriter -public class MissesScaleSelfWritable implements ScaleSelfWritable { - private String testString; - - public String getTestString() { - return testString; - } - - public void setTestString(String testString) { - this.testString = testString; - } -} diff --git a/scale/scale-codegen/src/test/resources/NonGenericScaleSelfWritable.java b/scale/scale-codegen/src/test/resources/NonGenericScaleSelfWritable.java deleted file mode 100644 index 8863e934..00000000 --- a/scale/scale-codegen/src/test/resources/NonGenericScaleSelfWritable.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.strategyobject.substrateclient.scale; - -import com.strategyobject.substrateclient.scale.annotation.ScaleWriter; - -@ScaleWriter -public class NonGenericScaleSelfWritable implements ScaleSelfWritable { -} diff --git a/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleDispatch.java b/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleDispatch.java new file mode 100644 index 00000000..ad1de565 --- /dev/null +++ b/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleDispatch.java @@ -0,0 +1,4 @@ +package com.strategyobject.substrateclient.scale; + +public interface ScaleDispatch { +} diff --git a/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleRegistryHelper.java b/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleRegistryHelper.java index 612a5f26..bc79a7d4 100644 --- a/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleRegistryHelper.java +++ b/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleRegistryHelper.java @@ -9,8 +9,10 @@ private ScaleRegistryHelper() { } @SuppressWarnings("unchecked") - public static ScaleReader resolveAndInjectOrNull(Class clazz, ScaleReader... dependencies) { - val target = (ScaleReader) ScaleReaderRegistry.getInstance().resolve(clazz); + public static ScaleReader resolveAndInjectOrNull(ScaleReaderRegistry registry, + Class clazz, + ScaleReader... dependencies) { + val target = (ScaleReader) registry.resolve(clazz); if (target == null) { return null; @@ -20,8 +22,10 @@ public static ScaleReader resolveAndInjectOrNull(Class clazz, ScaleRea } @SuppressWarnings("unchecked") - public static ScaleWriter resolveAndInjectOrNull(Class clazz, ScaleWriter... dependencies) { - val target = (ScaleWriter) ScaleWriterRegistry.getInstance().resolve(clazz); + public static ScaleWriter resolveAndInjectOrNull(ScaleWriterRegistry registry, + Class clazz, + ScaleWriter... dependencies) { + val target = (ScaleWriter) registry.resolve(clazz); if (target == null) { return null; diff --git a/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleSelfWritable.java b/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleSelfWritable.java deleted file mode 100644 index 13ae13c3..00000000 --- a/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleSelfWritable.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.strategyobject.substrateclient.scale; - -import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; -import lombok.NonNull; -import lombok.val; - -import java.io.IOException; -import java.io.OutputStream; - -public interface ScaleSelfWritable> { - @SuppressWarnings("unchecked") - default void write(@NonNull OutputStream stream) throws IOException { - val writer = (ScaleWriter) ScaleWriterRegistry - .getInstance() - .resolve(this.getClass()); - - writer.write((T) this, stream); - } -} diff --git a/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleUtils.java b/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleUtils.java index 13f74602..17bc87ae 100644 --- a/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleUtils.java +++ b/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleUtils.java @@ -1,8 +1,6 @@ package com.strategyobject.substrateclient.scale; -import com.strategyobject.substrateclient.common.utils.HexConverter; -import com.strategyobject.substrateclient.scale.registries.ScaleReaderRegistry; -import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.NonNull; import lombok.val; @@ -12,10 +10,8 @@ public final class ScaleUtils { - @SuppressWarnings("unchecked") - public static T fromBytes(byte @NonNull [] bytes, Class clazz) { + public static T fromBytes(byte @NonNull [] bytes, @NonNull ScaleReader reader) { val stream = new ByteArrayInputStream(bytes); - val reader = (ScaleReader) ScaleReaderRegistry.getInstance().resolve(clazz); try { return reader.read(stream); } catch (IOException e) { @@ -23,10 +19,8 @@ public static T fromBytes(byte @NonNull [] bytes, Class clazz) { } } - @SuppressWarnings("unchecked") - public static byte[] toBytes(T value, Class clazz) { + public static byte[] toBytes(T value, @NonNull ScaleWriter writer) { val stream = new ByteArrayOutputStream(); - val writer = (ScaleWriter) ScaleWriterRegistry.getInstance().resolve(clazz); try { writer.write(value, stream); } catch (IOException e) { @@ -36,37 +30,12 @@ public static byte[] toBytes(T value, Class clazz) { return stream.toByteArray(); } - public static > byte[] toBytes(ScaleSelfWritable value) { - val stream = new ByteArrayOutputStream(); - try { - value.write(stream); - } catch (IOException e) { - throw new RuntimeException(e); - } - - return stream.toByteArray(); - } - - public static String toHexString(@NonNull T value, @NonNull ScaleWriter writer) { - val stream = new ByteArrayOutputStream(); - - try { - writer.write(value, stream); - } catch (IOException e) { - throw new RuntimeException(e); - } - - return HexConverter.toHex(stream.toByteArray()); - } - public static T fromHexString(@NonNull String hex, @NonNull ScaleReader reader) { - val stream = new ByteArrayInputStream(HexConverter.toBytes(hex)); + return fromBytes(HexConverter.toBytes(hex), reader); + } - try { - return reader.read(stream); - } catch (IOException e) { - throw new RuntimeException(e); - } + public static String toHexString(T value, @NonNull ScaleWriter writer) { + return HexConverter.toHex(toBytes(value, writer)); } private ScaleUtils() { diff --git a/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleWriter.java b/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleWriter.java index befa8d7f..e08c3756 100644 --- a/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleWriter.java +++ b/scale/src/main/java/com/strategyobject/substrateclient/scale/ScaleWriter.java @@ -6,7 +6,7 @@ import java.io.OutputStream; public interface ScaleWriter { - void write(@NonNull T value, @NonNull OutputStream stream, ScaleWriter... writers) throws IOException; + void write(T value, @NonNull OutputStream stream, ScaleWriter... writers) throws IOException; default ScaleWriter inject(ScaleWriter... dependencies) { return (value, stream, writers) -> ScaleWriter.this.write(value, stream, dependencies); diff --git a/scale/src/main/java/com/strategyobject/substrateclient/scale/registries/ScaleReaderRegistry.java b/scale/src/main/java/com/strategyobject/substrateclient/scale/registries/ScaleReaderRegistry.java index 381be5cb..33e3cab6 100644 --- a/scale/src/main/java/com/strategyobject/substrateclient/scale/registries/ScaleReaderRegistry.java +++ b/scale/src/main/java/com/strategyobject/substrateclient/scale/registries/ScaleReaderRegistry.java @@ -1,7 +1,9 @@ package com.strategyobject.substrateclient.scale.registries; +import com.strategyobject.substrateclient.common.reflection.ClassUtils; import com.strategyobject.substrateclient.common.reflection.Scanner; import com.strategyobject.substrateclient.common.types.Array; +import com.strategyobject.substrateclient.common.types.AutoRegistry; import com.strategyobject.substrateclient.common.types.Result; import com.strategyobject.substrateclient.common.types.Unit; import com.strategyobject.substrateclient.common.types.union.*; @@ -11,23 +13,21 @@ import com.strategyobject.substrateclient.scale.readers.*; import com.strategyobject.substrateclient.scale.readers.union.*; import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.lang.reflect.InvocationTargetException; import java.math.BigInteger; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; -public final class ScaleReaderRegistry { - private static final Logger logger = LoggerFactory.getLogger(ScaleReaderRegistry.class); - private static final String ROOT_PREFIX = "com.strategyobject.substrateclient"; - private static volatile ScaleReaderRegistry instance; +@Slf4j +public class ScaleReaderRegistry implements AutoRegistry { private final Map, ScaleReader> readers; - private ScaleReaderRegistry() { + public ScaleReaderRegistry() { readers = new ConcurrentHashMap<>(128); register(new BoolReader(), ScaleType.Bool.class, Boolean.class, boolean.class); @@ -68,19 +68,6 @@ private ScaleReaderRegistry() { register(new LongArrayReader(), long[].class); register(new VoidReader(), Void.class, void.class); register(new UnitReader(), Unit.class); - - registerAnnotatedFrom(ROOT_PREFIX); - } - - public static ScaleReaderRegistry getInstance() { - if (instance == null) { - synchronized (ScaleReaderRegistry.class) { - if (instance == null) { - instance = new ScaleReaderRegistry(); - } - } - } - return instance; } public void registerAnnotatedFrom(String... prefixes) { @@ -93,12 +80,21 @@ public void registerAnnotatedFrom(String... prefixes) { try { val types = autoRegister.types(); - logger.info("Auto register reader {} for types: {}", reader, types); + log.info("Auto register reader {} for types: {}", reader, types); + + + ScaleReader readerInstance; + if (ClassUtils.hasDefaultConstructor(reader)) { + readerInstance = reader.newInstance(); + } else { + val ctor = reader.getConstructor(ScaleReaderRegistry.class); + readerInstance = ctor.newInstance(this); + } - final ScaleReader readerInstance = reader.newInstance(); register(readerInstance, types); - } catch (InstantiationException | IllegalAccessException e) { - logger.error("Auto registration error", e); + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | + InvocationTargetException e) { + log.error("Auto registration error", e); } }); } diff --git a/scale/src/main/java/com/strategyobject/substrateclient/scale/registries/ScaleWriterRegistry.java b/scale/src/main/java/com/strategyobject/substrateclient/scale/registries/ScaleWriterRegistry.java index fa775035..91c9e72f 100644 --- a/scale/src/main/java/com/strategyobject/substrateclient/scale/registries/ScaleWriterRegistry.java +++ b/scale/src/main/java/com/strategyobject/substrateclient/scale/registries/ScaleWriterRegistry.java @@ -1,34 +1,34 @@ package com.strategyobject.substrateclient.scale.registries; +import com.strategyobject.substrateclient.common.reflection.ClassUtils; import com.strategyobject.substrateclient.common.reflection.Scanner; import com.strategyobject.substrateclient.common.types.Array; +import com.strategyobject.substrateclient.common.types.AutoRegistry; import com.strategyobject.substrateclient.common.types.Result; import com.strategyobject.substrateclient.common.types.Unit; import com.strategyobject.substrateclient.common.types.union.*; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; +import com.strategyobject.substrateclient.scale.ScaleDispatch; import com.strategyobject.substrateclient.scale.ScaleType; import com.strategyobject.substrateclient.scale.ScaleWriter; import com.strategyobject.substrateclient.scale.annotation.AutoRegister; import com.strategyobject.substrateclient.scale.writers.*; import com.strategyobject.substrateclient.scale.writers.union.*; import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.lang.reflect.InvocationTargetException; import java.math.BigInteger; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; -public final class ScaleWriterRegistry { - private static final Logger logger = LoggerFactory.getLogger(ScaleWriterRegistry.class); - private static final String ROOT_PREFIX = "com.strategyobject.substrateclient"; - private static volatile ScaleWriterRegistry instance; +@Slf4j +public class ScaleWriterRegistry implements AutoRegistry { private final Map, ScaleWriter> writers; - private ScaleWriterRegistry() { + public ScaleWriterRegistry() { writers = new ConcurrentHashMap<>(128); register(new BoolWriter(), ScaleType.Bool.class, Boolean.class, boolean.class); @@ -69,20 +69,7 @@ private ScaleWriterRegistry() { register(new LongArrayWriter(), long[].class); register(new VoidWriter(), Void.class, void.class); register(new UnitWriter(), Unit.class); - register(new SelfWriter(), ScaleSelfWritable.class); - - registerAnnotatedFrom(ROOT_PREFIX); - } - - public static ScaleWriterRegistry getInstance() { - if (instance == null) { - synchronized (ScaleWriterRegistry.class) { - if (instance == null) { - instance = new ScaleWriterRegistry(); - } - } - } - return instance; + register(new DispatchingWriter<>(this), ScaleDispatch.class); } public void registerAnnotatedFrom(String... prefixes) { @@ -95,12 +82,20 @@ public void registerAnnotatedFrom(String... prefixes) { try { val types = autoRegister.types(); - logger.info("Auto register writer {} for types: {}", writer, types); + log.info("Auto register writer {} for types: {}", writer, types); + + ScaleWriter writerInstance; + if (ClassUtils.hasDefaultConstructor(writer)) { + writerInstance = writer.newInstance(); + } else { + val ctor = writer.getConstructor(ScaleWriterRegistry.class); + writerInstance = ctor.newInstance(this); + } - final ScaleWriter writerInstance = writer.newInstance(); register(writerInstance, types); - } catch (InstantiationException | IllegalAccessException e) { - logger.error("Auto registration error", e); + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | + InvocationTargetException e) { + log.error("Auto registration error", e); } }); } diff --git a/scale/src/main/java/com/strategyobject/substrateclient/scale/writers/DispatchingWriter.java b/scale/src/main/java/com/strategyobject/substrateclient/scale/writers/DispatchingWriter.java new file mode 100644 index 00000000..d87581e6 --- /dev/null +++ b/scale/src/main/java/com/strategyobject/substrateclient/scale/writers/DispatchingWriter.java @@ -0,0 +1,22 @@ +package com.strategyobject.substrateclient.scale.writers; + +import com.strategyobject.substrateclient.scale.ScaleWriter; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.val; + +import java.io.IOException; +import java.io.OutputStream; + +@RequiredArgsConstructor +public class DispatchingWriter implements ScaleWriter { + private final @NonNull ScaleWriterRegistry registry; + + @SuppressWarnings("unchecked") + @Override + public void write(@NonNull T value, @NonNull OutputStream stream, ScaleWriter... writers) throws IOException { + val writer = (ScaleWriter) registry.resolve(value.getClass()); + writer.write(value, stream, writers); + } +} diff --git a/scale/src/main/java/com/strategyobject/substrateclient/scale/writers/SelfWriter.java b/scale/src/main/java/com/strategyobject/substrateclient/scale/writers/SelfWriter.java deleted file mode 100644 index d0fa25ef..00000000 --- a/scale/src/main/java/com/strategyobject/substrateclient/scale/writers/SelfWriter.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.strategyobject.substrateclient.scale.writers; - -import com.google.common.base.Preconditions; -import com.strategyobject.substrateclient.scale.ScaleSelfWritable; -import com.strategyobject.substrateclient.scale.ScaleWriter; -import lombok.NonNull; - -import java.io.IOException; -import java.io.OutputStream; - -public class SelfWriter implements ScaleWriter> { - @Override - public void write(@NonNull ScaleSelfWritable value, @NonNull OutputStream stream, ScaleWriter... writers) throws IOException { - Preconditions.checkArgument(writers == null || writers.length == 0); - - value.write(stream); - } -} diff --git a/scale/src/main/java/com/strategyobject/substrateclient/scale/writers/VoidWriter.java b/scale/src/main/java/com/strategyobject/substrateclient/scale/writers/VoidWriter.java index 202ca033..c0dbbf6e 100644 --- a/scale/src/main/java/com/strategyobject/substrateclient/scale/writers/VoidWriter.java +++ b/scale/src/main/java/com/strategyobject/substrateclient/scale/writers/VoidWriter.java @@ -8,8 +8,7 @@ public class VoidWriter implements ScaleWriter { @Override - public void write(@NonNull Void value, @NonNull OutputStream stream, ScaleWriter... writers) { + public void write(Void value, @NonNull OutputStream stream, ScaleWriter... writers) { Preconditions.checkArgument(writers == null || writers.length == 0); } } - diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/ScaleReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/ScaleReaderTest.java index 083f07ee..c3970710 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/ScaleReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/ScaleReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.scale.readers.I8Reader; import com.strategyobject.substrateclient.scale.readers.OptionReader; import com.strategyobject.substrateclient.scale.readers.VecReader; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/ScaleWriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/ScaleWriterTest.java index ac15824e..82275d0c 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/ScaleWriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/ScaleWriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.scale.writers.I8Writer; import com.strategyobject.substrateclient.scale.writers.OptionWriter; import com.strategyobject.substrateclient.scale.writers.VecWriter; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/ArrayReadersTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/ArrayReadersTest.java index 7fa6946f..b40b30de 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/ArrayReadersTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/ArrayReadersTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.scale.ScaleReader; import com.strategyobject.substrateclient.tests.TestSuite; import lombok.AccessLevel; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/BoolReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/BoolReaderTest.java index 87fa2faf..b95c4b69 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/BoolReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/BoolReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/CompactBigIntegerReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/CompactBigIntegerReaderTest.java index c23bdd75..716e155c 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/CompactBigIntegerReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/CompactBigIntegerReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/CompactIntegerReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/CompactIntegerReaderTest.java index b80f426a..656a9a11 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/CompactIntegerReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/CompactIntegerReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.api.Test; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I128ReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I128ReaderTest.java index 494e458f..7372e973 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I128ReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I128ReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I16ReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I16ReaderTest.java index fb224573..9b61fd13 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I16ReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I16ReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I32ReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I32ReaderTest.java index 6b321e1e..071eb115 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I32ReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I32ReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I64ReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I64ReaderTest.java index b0d4310a..6607cb35 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I64ReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I64ReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I8ReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I8ReaderTest.java index 3cde5433..4037b9bd 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I8ReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/I8ReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/OptionBoolReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/OptionBoolReaderTest.java index f17cf054..b7b9e36a 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/OptionBoolReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/OptionBoolReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/OptionReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/OptionReaderTest.java index 5e5da3ae..e390a63d 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/OptionReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/OptionReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.api.Test; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/ResultReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/ResultReaderTest.java index eceae7e5..2a854917 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/ResultReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/ResultReaderTest.java @@ -1,7 +1,7 @@ package com.strategyobject.substrateclient.scale.readers; import com.strategyobject.substrateclient.common.types.Result; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.api.Test; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/StringReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/StringReaderTest.java index 8fe2e665..59d659d1 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/StringReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/StringReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.api.Test; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U128ReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U128ReaderTest.java index a8460851..8dc4aa90 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U128ReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U128ReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U16ReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U16ReaderTest.java index 63de19ac..e1c33c17 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U16ReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U16ReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U32ReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U32ReaderTest.java index 5f69d9e7..ee4cbbd2 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U32ReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U32ReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U64ReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U64ReaderTest.java index df782649..1ad3a461 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U64ReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U64ReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U8ReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U8ReaderTest.java index 1187b358..adb12ee2 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U8ReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/U8ReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/VecReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/VecReaderTest.java index 6f25633b..a3ded195 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/VecReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/VecReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.api.Test; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/union/Union1ReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/union/Union1ReaderTest.java index fd99a22b..ff22b9c8 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/union/Union1ReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/union/Union1ReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers.union; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.scale.readers.U8Reader; import lombok.SneakyThrows; import lombok.val; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/union/Union2ReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/union/Union2ReaderTest.java index f441b5e9..295405d1 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/union/Union2ReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/union/Union2ReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers.union; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.scale.readers.BoolReader; import com.strategyobject.substrateclient.scale.readers.U8Reader; import com.strategyobject.substrateclient.scale.readers.VoidReader; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/union/Union3ReaderTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/union/Union3ReaderTest.java index 514d2545..0e84eb6d 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/union/Union3ReaderTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/readers/union/Union3ReaderTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.readers.union; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.scale.readers.BoolReader; import com.strategyobject.substrateclient.scale.readers.U8Reader; import com.strategyobject.substrateclient.scale.readers.VoidReader; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/substitutes/TestDispatch.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/substitutes/TestDispatch.java new file mode 100644 index 00000000..c2086c26 --- /dev/null +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/substitutes/TestDispatch.java @@ -0,0 +1,10 @@ +package com.strategyobject.substrateclient.scale.substitutes; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class TestDispatch { + private final String value; +} diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/substitutes/TestDispatchWriter.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/substitutes/TestDispatchWriter.java new file mode 100644 index 00000000..d7b07649 --- /dev/null +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/substitutes/TestDispatchWriter.java @@ -0,0 +1,22 @@ +package com.strategyobject.substrateclient.scale.substitutes; + +import com.strategyobject.substrateclient.scale.ScaleWriter; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.val; + +import java.io.IOException; +import java.io.OutputStream; + +@RequiredArgsConstructor +public class TestDispatchWriter implements ScaleWriter { + private final ScaleWriterRegistry scaleWriterRegistry; + + @SuppressWarnings("unchecked") + @Override + public void write(@NonNull TestDispatch value, @NonNull OutputStream stream, ScaleWriter... writers) throws IOException { + val writer = (ScaleWriter) scaleWriterRegistry.resolve(String.class); + writer.write(value.getValue(), stream); + } +} diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/ArrayWritersTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/ArrayWritersTest.java index 8feb4e7c..04956121 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/ArrayWritersTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/ArrayWritersTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import com.strategyobject.substrateclient.scale.ScaleWriter; import com.strategyobject.substrateclient.tests.TestSuite; import lombok.AccessLevel; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/BoolWriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/BoolWriterTest.java index 3c6cdd03..a086e91b 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/BoolWriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/BoolWriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/CompactBigIntegerWriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/CompactBigIntegerWriterTest.java index b08923cb..f6837ff6 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/CompactBigIntegerWriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/CompactBigIntegerWriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/CompactIntegerWriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/CompactIntegerWriterTest.java index a99ba2f8..1dc3be26 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/CompactIntegerWriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/CompactIntegerWriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.api.Test; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/DispatchingWriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/DispatchingWriterTest.java new file mode 100644 index 00000000..0e3b46fc --- /dev/null +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/DispatchingWriterTest.java @@ -0,0 +1,33 @@ +package com.strategyobject.substrateclient.scale.writers; + +import com.strategyobject.substrateclient.common.convert.HexConverter; +import com.strategyobject.substrateclient.scale.ScaleDispatch; +import com.strategyobject.substrateclient.scale.ScaleWriter; +import com.strategyobject.substrateclient.scale.registries.ScaleWriterRegistry; +import com.strategyobject.substrateclient.scale.substitutes.TestDispatch; +import com.strategyobject.substrateclient.scale.substitutes.TestDispatchWriter; +import lombok.val; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class DispatchingWriterTest { + private final ScaleWriterRegistry registry = new ScaleWriterRegistry() {{ + register(new TestDispatchWriter(this), TestDispatch.class); + }}; + + @SuppressWarnings("unchecked") + @Test + void write() throws IOException { + val writer = (ScaleWriter) registry.resolve(ScaleDispatch.class); + + val stream = new ByteArrayOutputStream(); + writer.write(new TestDispatch("test"), stream); + val actual = HexConverter.toHex(stream.toByteArray()); + + assertEquals("0x1074657374", actual); + } +} \ No newline at end of file diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I128WriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I128WriterTest.java index ddcf8de4..59bd146c 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I128WriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I128WriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I16WriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I16WriterTest.java index fa9fa36e..ef96ca73 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I16WriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I16WriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I32WriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I32WriterTest.java index 00777029..9783d1df 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I32WriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I32WriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I64WriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I64WriterTest.java index 06a275ff..27133d69 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I64WriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I64WriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I8WriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I8WriterTest.java index 3ad06895..d499e988 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I8WriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/I8WriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/StringWriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/StringWriterTest.java index 17843c6a..72b99dca 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/StringWriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/StringWriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.api.Test; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U128WriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U128WriterTest.java index b4b32ba8..9a0101e1 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U128WriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U128WriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U16WriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U16WriterTest.java index 994b07d5..dd1b21b4 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U16WriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U16WriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U32WriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U32WriterTest.java index df08a05b..0f2335fe 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U32WriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U32WriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U64WriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U64WriterTest.java index 9b666915..33d64876 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U64WriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U64WriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U8WriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U8WriterTest.java index fd3dd2cf..e2996a0f 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U8WriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/U8WriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.params.ParameterizedTest; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/VecWriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/VecWriterTest.java index a31fb15c..7718057d 100644 --- a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/VecWriterTest.java +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/VecWriterTest.java @@ -1,6 +1,6 @@ package com.strategyobject.substrateclient.scale.writers; -import com.strategyobject.substrateclient.common.utils.HexConverter; +import com.strategyobject.substrateclient.common.convert.HexConverter; import lombok.SneakyThrows; import lombok.val; import org.junit.jupiter.api.Test; diff --git a/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/VoidWriterTest.java b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/VoidWriterTest.java new file mode 100644 index 00000000..f2d3024c --- /dev/null +++ b/scale/src/test/java/com/strategyobject/substrateclient/scale/writers/VoidWriterTest.java @@ -0,0 +1,25 @@ +package com.strategyobject.substrateclient.scale.writers; + +import com.strategyobject.substrateclient.common.convert.HexConverter; +import lombok.SneakyThrows; +import lombok.val; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class VoidWriterTest { + + private final VoidWriter voidWriter = new VoidWriter(); + + @SneakyThrows + @Test + void write() { + val stream = new ByteArrayOutputStream(); + voidWriter.write(null, stream); + val actual = HexConverter.toHex(stream.toByteArray()); + + assertEquals("0x", actual); + } +} \ No newline at end of file diff --git a/tests/build.gradle b/tests/build.gradle index dfab4466..5d2ac6bf 100644 --- a/tests/build.gradle +++ b/tests/build.gradle @@ -1,4 +1,4 @@ dependencies { - implementation 'org.testcontainers:testcontainers:1.17.1' + implementation 'org.testcontainers:testcontainers:1.17.2' implementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' } \ No newline at end of file diff --git a/transport/build.gradle b/transport/build.gradle index a01a0c33..f7f793a5 100644 --- a/transport/build.gradle +++ b/transport/build.gradle @@ -6,8 +6,8 @@ dependencies { testImplementation project(':tests') testImplementation 'ch.qos.logback:logback-classic:1.2.11' - testImplementation 'org.testcontainers:testcontainers:1.17.1' - testImplementation 'org.testcontainers:junit-jupiter:1.17.1' - testImplementation 'org.testcontainers:toxiproxy:1.17.1' + testImplementation 'org.testcontainers:testcontainers:1.17.2' + testImplementation 'org.testcontainers:junit-jupiter:1.17.2' + testImplementation 'org.testcontainers:toxiproxy:1.17.2' testImplementation 'org.awaitility:awaitility:4.2.0' } \ No newline at end of file diff --git a/transport/src/main/java/com/strategyobject/substrateclient/transport/ws/WsProvider.java b/transport/src/main/java/com/strategyobject/substrateclient/transport/ws/WsProvider.java index 92edd0e0..f67a1b8b 100644 --- a/transport/src/main/java/com/strategyobject/substrateclient/transport/ws/WsProvider.java +++ b/transport/src/main/java/com/strategyobject/substrateclient/transport/ws/WsProvider.java @@ -19,6 +19,7 @@ import java.util.*; import java.util.concurrent.*; import java.util.function.BiConsumer; +import java.util.function.Supplier; @Getter @Setter @@ -140,8 +141,8 @@ public synchronized CompletableFuture connect() { this.status = ProviderStatus.CONNECTING; - val whenConnected = new CompletableFuture(); - this.whenConnected = whenConnected; + val whenConnectedFuture = new CompletableFuture(); + this.whenConnected = whenConnectedFuture; try { val ws = WebSocket.builder() @@ -156,19 +157,19 @@ public synchronized CompletableFuture connect() { this.webSocket = ws; this.eventEmitter.once(ProviderInterfaceEmitted.CONNECTED, _x -> { - whenConnected.complete(null); + whenConnectedFuture.complete(null); this.whenConnected = null; }); ws.connect(); } catch (Exception ex) { log.error("Connect error", ex); - whenConnected.completeExceptionally(ex); + whenConnectedFuture.completeExceptionally(ex); this.emit(ProviderInterfaceEmitted.ERROR, ex); this.whenConnected = null; this.status = ProviderStatus.DISCONNECTED; } - return whenConnected; + return whenConnectedFuture; } /** @@ -188,8 +189,8 @@ public synchronized CompletableFuture disconnect() { return inProgress; } - val whenDisconnected = new CompletableFuture(); - this.whenDisconnected = whenDisconnected; + val whenDisconnectedFuture = new CompletableFuture(); + this.whenDisconnected = whenDisconnectedFuture; // switch off autoConnect, we are in manual mode now this.autoConnectMs = 0; @@ -200,7 +201,7 @@ public synchronized CompletableFuture disconnect() { ws.close(CloseFrame.NORMAL); } - return whenDisconnected; + return whenDisconnectedFuture; } /** @@ -370,9 +371,9 @@ private synchronized void onSocketClose(int code, String reason) { this.webSocket = null; this.status = ProviderStatus.DISCONNECTED; this.emit(ProviderInterfaceEmitted.DISCONNECTED); - val whenDisconnected = this.whenDisconnected; - if (whenDisconnected != null) { - whenDisconnected.complete(null); + val whenDisconnectedFuture = this.whenDisconnected; + if (whenDisconnectedFuture != null) { + whenDisconnectedFuture.complete(null); this.whenDisconnected = null; } @@ -400,7 +401,7 @@ private void onSocketMessage(String message) { private void onSocketMessageResult(JsonRpcResponseSingle response) { val id = response.getId(); - val handler = (WsStateAwaiting) this.handlers.get(id); + val handler = this.handlers.get(id); if (handler == null) { log.error("Unable to find handler for id={}", id); return; @@ -482,13 +483,13 @@ public void close() { } private void resubscribe() { - Map subscriptions = new HashMap<>(this.subscriptions); + Map currentSubscriptions = new HashMap<>(this.subscriptions); this.subscriptions.clear(); try { CompletableFuture.allOf( - subscriptions.values() + currentSubscriptions.values() .stream() // only re-create subscriptions which are not in author (only area where // transactions are created, i.e. submissions such as 'author_submitAndWatchExtrinsic' @@ -514,7 +515,9 @@ private void resubscribe() { } } - public static class Builder { + public static class Builder implements Supplier { + private static final String DEFAULT_URI = "ws://127.0.0.1:9944"; + private URI endpoint; private int autoConnectMs = 2500; private Map headers = null; @@ -523,9 +526,9 @@ public static class Builder { Builder() { try { - endpoint = new URI("ws://127.0.0.1:9944"); - } catch (URISyntaxException ex) { - ex.printStackTrace(); + endpoint = new URI(DEFAULT_URI); + } catch (URISyntaxException e) { + throw new RuntimeException(e); } } @@ -579,5 +582,10 @@ public WsProvider build() { this.heartbeatInterval, this.responseTimeoutInMs); } + + @Override + public WsProvider get() { + return build(); + } } }