diff --git a/generator/src/main/java/org/sudu/protogen/ProtogenGenerator.java b/generator/src/main/java/org/sudu/protogen/ProtogenGenerator.java index 5b4576a..bcee63d 100644 --- a/generator/src/main/java/org/sudu/protogen/ProtogenGenerator.java +++ b/generator/src/main/java/org/sudu/protogen/ProtogenGenerator.java @@ -11,8 +11,6 @@ import org.sudu.protogen.generator.GenerationContext; import org.sudu.protogen.generator.GenerationRequest; import org.sudu.protogen.generator.GenerationResult; -import org.sudu.protogen.generator.field.processors.FieldTypeProcessor; -import org.sudu.protogen.generator.type.processors.TypeProcessor; import org.sudu.protogen.plugin.Generator; import org.sudu.protogen.plugin.GeneratorException; @@ -42,11 +40,7 @@ private GenerationResult generate(GenerationRequest request, Configuration confi var filesToGenerate = allFiles.stream() .filter(file -> request.filesToGenerateNames().contains(file.getName())) .toList(); - var context = new GenerationContext( - configuration, - TypeProcessor.Chain.getProcessingChain(), - FieldTypeProcessor.Chain.getProcessingChain() - ); + var context = new GenerationContext(configuration); return new org.sudu.protogen.generator.Generator(context, filesToGenerate).generate(); } diff --git a/generator/src/main/java/org/sudu/protogen/descriptors/Descriptor.java b/generator/src/main/java/org/sudu/protogen/descriptors/Descriptor.java new file mode 100644 index 0000000..2051a6c --- /dev/null +++ b/generator/src/main/java/org/sudu/protogen/descriptors/Descriptor.java @@ -0,0 +1,4 @@ +package org.sudu.protogen.descriptors; + +public interface Descriptor { +} diff --git a/generator/src/main/java/org/sudu/protogen/descriptors/Enum.java b/generator/src/main/java/org/sudu/protogen/descriptors/Enum.java index 819ffc5..31e8683 100644 --- a/generator/src/main/java/org/sudu/protogen/descriptors/Enum.java +++ b/generator/src/main/java/org/sudu/protogen/descriptors/Enum.java @@ -9,7 +9,7 @@ import java.util.Objects; import java.util.Optional; -public class Enum extends EnumOrMessage { +public class Enum extends EnumOrMessage implements Descriptor { private final Descriptors.EnumDescriptor enumDescriptor; diff --git a/generator/src/main/java/org/sudu/protogen/descriptors/EnumOrMessage.java b/generator/src/main/java/org/sudu/protogen/descriptors/EnumOrMessage.java index 530f5bd..bba5a53 100644 --- a/generator/src/main/java/org/sudu/protogen/descriptors/EnumOrMessage.java +++ b/generator/src/main/java/org/sudu/protogen/descriptors/EnumOrMessage.java @@ -10,7 +10,7 @@ import java.util.List; import java.util.Optional; -public abstract class EnumOrMessage { +public abstract class EnumOrMessage implements Descriptor { public abstract @NotNull String getName(); diff --git a/generator/src/main/java/org/sudu/protogen/descriptors/Field.java b/generator/src/main/java/org/sudu/protogen/descriptors/Field.java index 82481aa..228209f 100644 --- a/generator/src/main/java/org/sudu/protogen/descriptors/Field.java +++ b/generator/src/main/java/org/sudu/protogen/descriptors/Field.java @@ -8,7 +8,7 @@ import java.util.Objects; import java.util.Optional; -public class Field { +public class Field implements Descriptor { private final Descriptors.FieldDescriptor descriptor; diff --git a/generator/src/main/java/org/sudu/protogen/descriptors/File.java b/generator/src/main/java/org/sudu/protogen/descriptors/File.java index c2c5ded..9826169 100644 --- a/generator/src/main/java/org/sudu/protogen/descriptors/File.java +++ b/generator/src/main/java/org/sudu/protogen/descriptors/File.java @@ -13,7 +13,7 @@ import java.util.Optional; import java.util.stream.Stream; -public class File { +public class File implements Descriptor { private final Descriptors.FileDescriptor fileDescriptor; diff --git a/generator/src/main/java/org/sudu/protogen/descriptors/Message.java b/generator/src/main/java/org/sudu/protogen/descriptors/Message.java index efac948..9a5d4d5 100644 --- a/generator/src/main/java/org/sudu/protogen/descriptors/Message.java +++ b/generator/src/main/java/org/sudu/protogen/descriptors/Message.java @@ -10,7 +10,7 @@ import java.util.Optional; import java.util.stream.Stream; -public class Message extends EnumOrMessage { +public class Message extends EnumOrMessage implements Descriptor { private final Descriptors.Descriptor messageDescriptor; diff --git a/generator/src/main/java/org/sudu/protogen/descriptors/Method.java b/generator/src/main/java/org/sudu/protogen/descriptors/Method.java index a0d613f..7261cd1 100644 --- a/generator/src/main/java/org/sudu/protogen/descriptors/Method.java +++ b/generator/src/main/java/org/sudu/protogen/descriptors/Method.java @@ -9,7 +9,7 @@ import java.util.Objects; import java.util.Optional; -public class Method { +public class Method implements Descriptor { private final Descriptors.MethodDescriptor methodDescriptor; diff --git a/generator/src/main/java/org/sudu/protogen/descriptors/RepeatedContainer.java b/generator/src/main/java/org/sudu/protogen/descriptors/RepeatedContainer.java index 90d471c..a2505fc 100644 --- a/generator/src/main/java/org/sudu/protogen/descriptors/RepeatedContainer.java +++ b/generator/src/main/java/org/sudu/protogen/descriptors/RepeatedContainer.java @@ -9,7 +9,7 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; -public enum RepeatedContainer { +public enum RepeatedContainer implements Descriptor { LIST(ClassName.get(List.class)) { @Override diff --git a/generator/src/main/java/org/sudu/protogen/descriptors/Service.java b/generator/src/main/java/org/sudu/protogen/descriptors/Service.java index cf04b6e..f8519c4 100644 --- a/generator/src/main/java/org/sudu/protogen/descriptors/Service.java +++ b/generator/src/main/java/org/sudu/protogen/descriptors/Service.java @@ -9,7 +9,7 @@ import java.util.Objects; import java.util.Optional; -public class Service { +public class Service implements Descriptor { private final Descriptors.ServiceDescriptor serviceDescriptor; diff --git a/generator/src/main/java/org/sudu/protogen/generator/DescriptorGenerator.java b/generator/src/main/java/org/sudu/protogen/generator/DescriptorGenerator.java new file mode 100644 index 0000000..072e4bf --- /dev/null +++ b/generator/src/main/java/org/sudu/protogen/generator/DescriptorGenerator.java @@ -0,0 +1,35 @@ +package org.sudu.protogen.generator; + +import org.sudu.protogen.descriptors.Descriptor; + +import java.util.WeakHashMap; + +public interface DescriptorGenerator { + + T generate(D descriptor); + + default DescriptorGenerator withCache() { + return new CachedGenerator<>(this); + } + + class CachedGenerator implements DescriptorGenerator { + + private final WeakHashMap cache; + + private final DescriptorGenerator generator; + + public CachedGenerator(DescriptorGenerator generator, WeakHashMap cache) { + this.cache = cache; + this.generator = generator; + } + + public CachedGenerator(DescriptorGenerator generator) { + this(generator, new WeakHashMap<>()); + } + + public final T generate(D descriptor) { + return cache.computeIfAbsent(descriptor, generator::generate); + } + } + +} diff --git a/generator/src/main/java/org/sudu/protogen/generator/EnumOrMessageGenerator.java b/generator/src/main/java/org/sudu/protogen/generator/EnumOrMessageGenerator.java deleted file mode 100644 index 46f3209..0000000 --- a/generator/src/main/java/org/sudu/protogen/generator/EnumOrMessageGenerator.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.sudu.protogen.generator; - -import com.squareup.javapoet.TypeSpec; -import org.sudu.protogen.descriptors.Enum; -import org.sudu.protogen.descriptors.EnumOrMessage; -import org.sudu.protogen.descriptors.Message; -import org.sudu.protogen.generator.enumeration.EnumGenerator; -import org.sudu.protogen.generator.message.MessageGenerator; - -public class EnumOrMessageGenerator { - - private final GenerationContext context; - - private final EnumOrMessage descriptor; - - public EnumOrMessageGenerator(GenerationContext context, EnumOrMessage descriptor) { - this.context = context; - this.descriptor = descriptor; - } - - public TypeSpec generate() { - if (descriptor instanceof Message msg) { - return new MessageGenerator(context, msg).generate(); - } - if (descriptor instanceof Enum en) { - return new EnumGenerator(context, en).generate(); - } - throw new IllegalStateException(); - } -} diff --git a/generator/src/main/java/org/sudu/protogen/generator/GenerationContext.java b/generator/src/main/java/org/sudu/protogen/generator/GenerationContext.java index 8500cf9..e597679 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/GenerationContext.java +++ b/generator/src/main/java/org/sudu/protogen/generator/GenerationContext.java @@ -1,23 +1,90 @@ package org.sudu.protogen.generator; +import com.squareup.javapoet.TypeSpec; import org.sudu.protogen.config.Configuration; -import org.sudu.protogen.descriptors.EnumOrMessage; -import org.sudu.protogen.descriptors.Field; +import org.sudu.protogen.descriptors.Enum; +import org.sudu.protogen.descriptors.*; +import org.sudu.protogen.generator.client.ClientGenerator; +import org.sudu.protogen.generator.enumeration.EnumGenerator; +import org.sudu.protogen.generator.field.FieldGenerator; +import org.sudu.protogen.generator.field.FieldProcessingResult; import org.sudu.protogen.generator.field.processors.FieldTypeProcessor; +import org.sudu.protogen.generator.message.MessageGenerator; +import org.sudu.protogen.generator.server.ServiceGenerator; import org.sudu.protogen.generator.type.TypeModel; import org.sudu.protogen.generator.type.processors.TypeProcessor; -public record GenerationContext( - Configuration configuration, - TypeProcessor typeProcessor, - FieldTypeProcessor fieldTypeProcessor -) { +public final class GenerationContext { - public TypeModel processType(EnumOrMessage enumOrMessage) { - return typeProcessor.processType(enumOrMessage, configuration); + private final Configuration configuration; + private final GeneratorsHolder holder; + private final TypeManager typeManager; + + public GenerationContext(Configuration configuration) { + this.configuration = configuration; + this.holder = new GeneratorsHolder(); + this.typeManager = new TypeManager(); + } + + public Configuration configuration() { + return configuration; + } + + public GeneratorsHolder generatorsHolder() { + return holder; + } + + public TypeManager typeManager() { + return typeManager; + } + + public class TypeManager { + + private final FieldTypeProcessor fieldTypeProcessor = FieldTypeProcessor.Chain.getProcessingChain(GenerationContext.this); + + private final TypeProcessor typeProcessor = TypeProcessor.Chain.getProcessingChain(GenerationContext.this); + + public TypeModel processType(EnumOrMessage enumOrMessage) { + return typeProcessor.processType(enumOrMessage); + } + + public TypeModel processType(Field field) { + return fieldTypeProcessor.processType(field); + } } - public TypeModel processType(Field field) { - return fieldTypeProcessor.processType(field, this); + public class GeneratorsHolder { + + private final DescriptorGenerator fieldGenerator = new FieldGenerator(GenerationContext.this).withCache(); + private final DescriptorGenerator messageGenerator = new MessageGenerator(GenerationContext.this).withCache(); + private final DescriptorGenerator enumGenerator = new EnumGenerator(GenerationContext.this).withCache(); + private final DescriptorGenerator clientGenerator = new ClientGenerator(GenerationContext.this).withCache(); + private final DescriptorGenerator serviceGenerator = new ServiceGenerator(GenerationContext.this).withCache(); + + public FieldProcessingResult field(Field field) { + return fieldGenerator.generate(field); + } + + public TypeSpec generate(Enum anEnum) { + return enumGenerator.generate(anEnum); + } + + public TypeSpec generate(Message message) { + return messageGenerator.generate(message); + } + + public TypeSpec generate(EnumOrMessage enumOrMessage) { + if (enumOrMessage instanceof Enum en) return generate(en); + if (enumOrMessage instanceof Message msg) return generate(msg); + throw new IllegalStateException(); + } + + public TypeSpec generateClient(Service service) { + return clientGenerator.generate(service); + } + + public TypeSpec generateService(Service service) { + return serviceGenerator.generate(service); + } } } diff --git a/generator/src/main/java/org/sudu/protogen/generator/Generator.java b/generator/src/main/java/org/sudu/protogen/generator/Generator.java index b7ee376..1c8166d 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/Generator.java +++ b/generator/src/main/java/org/sudu/protogen/generator/Generator.java @@ -7,8 +7,6 @@ import org.sudu.protogen.descriptors.EnumOrMessage; import org.sudu.protogen.descriptors.File; import org.sudu.protogen.descriptors.Service; -import org.sudu.protogen.generator.client.ClientGenerator; -import org.sudu.protogen.generator.server.BaseServiceGenerator; import java.io.IOException; import java.util.ArrayList; @@ -50,7 +48,7 @@ private List generateFiles() { String packageName = file.getGeneratePackage(); for (EnumOrMessage type : file.getNested()) { if (!type.doGenerate()) continue; - result.add(JavaFile.builder(packageName, new EnumOrMessageGenerator(context, type).generate()) + result.add(JavaFile.builder(packageName, context.generatorsHolder().generate(type)) .indent(getIndentation()) .build() ); @@ -59,11 +57,11 @@ private List generateFiles() { if (!service.doGenerate()) { continue; } - TypeSpec clientTypeSpec = new ClientGenerator(context, service).generate(); + TypeSpec clientTypeSpec = context.generatorsHolder().generateClient(service); result.add(JavaFile.builder(packageName, clientTypeSpec) .indent(getIndentation()) .build()); - TypeSpec serviceTypeSpec = new BaseServiceGenerator(context, service).generate(); + TypeSpec serviceTypeSpec = context.generatorsHolder().generateService(service); result.add(JavaFile.builder(packageName, serviceTypeSpec) .indent(getIndentation()) .build()); diff --git a/generator/src/main/java/org/sudu/protogen/generator/client/ApiMethodGeneratorBase.java b/generator/src/main/java/org/sudu/protogen/generator/client/ApiMethodGeneratorBase.java index 017230d..50f3b10 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/client/ApiMethodGeneratorBase.java +++ b/generator/src/main/java/org/sudu/protogen/generator/client/ApiMethodGeneratorBase.java @@ -93,7 +93,7 @@ private CodeBlock buildRequest(List params) { @NotNull private CodeBlock buildNonDomainRequest(ClassName requestProtoType) { List processedFields = method.getInputType().getFields().stream() - .map(field -> new FieldGenerator(context, field).generate()) + .map(field -> context.generatorsHolder().field(field)) .filter(FieldProcessingResult::isNonVoid) .toList(); CodeBlock builder = new ToGrpcMethodGenerator(context, requestProtoType, processedFields, false).builder("requestBuilder"); diff --git a/generator/src/main/java/org/sudu/protogen/generator/client/ClientGenerator.java b/generator/src/main/java/org/sudu/protogen/generator/client/ClientGenerator.java index 39b3807..04add93 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/client/ClientGenerator.java +++ b/generator/src/main/java/org/sudu/protogen/generator/client/ClientGenerator.java @@ -3,6 +3,7 @@ import com.squareup.javapoet.*; import org.sudu.protogen.descriptors.Method; import org.sudu.protogen.descriptors.Service; +import org.sudu.protogen.generator.DescriptorGenerator; import org.sudu.protogen.generator.GenerationContext; import org.sudu.protogen.generator.type.RepeatedType; import org.sudu.protogen.generator.type.TypeModel; @@ -14,7 +15,7 @@ import java.util.List; import java.util.stream.Stream; -public class ClientGenerator { +public class ClientGenerator implements DescriptorGenerator { public static final String modificationNotice = """ The client was generated by protogen. If you want to add some logic, mark the service using @@ -25,26 +26,21 @@ public class ClientGenerator { private final GenerationContext context; - private final Service service; - - private final FieldSpec stubField; - - public ClientGenerator(GenerationContext context, Service service) { + public ClientGenerator(GenerationContext context) { this.context = context; - this.service = service; - this.stubField = FieldSpec.builder(service.blockingStubClass(), "blockingStub", Modifier.PRIVATE, Modifier.FINAL).build(); } - public TypeSpec generate() { - + @Override + public TypeSpec generate(Service service) { + FieldSpec stubField = FieldSpec.builder(service.blockingStubClass(), "blockingStub", Modifier.PRIVATE, Modifier.FINAL).build(); TypeSpec.Builder builder = TypeSpec.classBuilder(service.generatedClientName()) .addModifiers(Modifier.PUBLIC) .addField(stubField) .addAnnotation(AnnotationSpec.builder(ClassName.get(Generated.class)).addMember("value", CodeBlock.of("\"protogen\"")).build()) - .addMethods(generateConstructors()) + .addMethods(generateConstructors(service)) .addMethods(service.getMethods().stream() .filter(Method::doGenerate) - .flatMap(this::generateRpcMethod) + .flatMap(m -> generateRpcMethod(stubField, m)) .toList() ); if (service.isAbstract()) { @@ -55,7 +51,7 @@ public TypeSpec generate() { return builder.build(); } - private List generateConstructors() { + private List generateConstructors(Service service) { return List.of( MethodSpec.constructorBuilder() .addModifiers(Modifier.PUBLIC) @@ -70,21 +66,21 @@ private List generateConstructors() { ); } - private Stream generateRpcMethod(Method method) { + private Stream generateRpcMethod(FieldSpec stubField, Method method) { TypeModel returnType = getMethodReturnType(method); - TypeModel requestType = context.processType(method.getInputType()); + TypeModel requestType = context.typeManager().processType(method.getInputType()); MethodSpec publicApi = new ApiMethodGeneratorBase(context, method, returnType, requestType).generate(); MethodSpec grpcRequestMethod = new StubCallMethodGenerator(context, method, returnType, stubField).generate(); return Stream.of(grpcRequestMethod, publicApi); } protected TypeModel getMethodReturnType(Method method) { - var responseType = context.processType(method.getOutputType()); + var responseType = context.typeManager().processType(method.getOutputType()); TypeModel type; if (responseType != null) { type = responseType; } else if (method.doUnfoldResponse(responseType)) { - type = new UnfoldedType(context.processType(method.unfoldedResponseField()), method.getOutputType()); + type = new UnfoldedType(context.typeManager().processType(method.unfoldedResponseField()), method.getOutputType()); } else if (method.getOutputType().getFields().isEmpty()) { type = new VoidType(); } else { diff --git a/generator/src/main/java/org/sudu/protogen/generator/enumeration/EnumGenerator.java b/generator/src/main/java/org/sudu/protogen/generator/enumeration/EnumGenerator.java index da69b71..a5dd107 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/enumeration/EnumGenerator.java +++ b/generator/src/main/java/org/sudu/protogen/generator/enumeration/EnumGenerator.java @@ -3,73 +3,78 @@ import com.squareup.javapoet.*; import org.jetbrains.annotations.NotNull; import org.sudu.protogen.descriptors.Enum; +import org.sudu.protogen.generator.DescriptorGenerator; import org.sudu.protogen.generator.GenerationContext; +import org.sudu.protogen.utils.Poem; import javax.lang.model.element.Modifier; -public class EnumGenerator { +public class EnumGenerator implements DescriptorGenerator { private final GenerationContext context; - private final Enum anEnum; - private final TypeName protoType; - private final TypeName generatedType; - public EnumGenerator(GenerationContext context, Enum anEnum) { + public EnumGenerator(GenerationContext context) { this.context = context; - this.anEnum = anEnum; - this.protoType = anEnum.getProtobufTypeName(); - this.generatedType = anEnum.getDomainTypeName(context.configuration().namingManager()); } - public TypeSpec generate() { + public TypeSpec generate(Enum anEnum) { ClassName domainTypeName = anEnum.getDomainTypeName(context.configuration().namingManager()); - var builder = TypeSpec.enumBuilder(domainTypeName.simpleName()) + TypeSpec.Builder builder = TypeSpec.enumBuilder(domainTypeName.simpleName()) .addModifiers(Modifier.PUBLIC); + anEnum.getValues().stream() .filter(val -> !val.isUnused()) .map(this::getNameForValue) .forEach(builder::addEnumConstant); - builder.addMethod(generateToGrpcMethod()); - builder.addMethod(generateFromGrpcMethod()); + + addMethods(anEnum, builder); + return builder.build(); } + private void addMethods(Enum anEnum, TypeSpec.Builder builder) { + TypeName protoType = anEnum.getProtobufTypeName(); + TypeName generatedType = anEnum.getDomainTypeName(context.configuration().namingManager()); + builder.addMethod(generateToGrpcMethod(anEnum, protoType)); + builder.addMethod(generateFromGrpcMethod(anEnum, generatedType, protoType)); + } + @NotNull private String getNameForValue(Enum.Value descriptor) { return descriptor.generatedName(); } - private MethodSpec generateToGrpcMethod() { - CodeBlock.Builder switchBlock = CodeBlock.builder().add("switch (this) {$>\n"); - for (var value : anEnum.getValues()) { - if (value.isUnused()) continue; - switchBlock.add("case $L -> $T.$L;\n", getNameForValue(value), protoType, value.getName()); - } - switchBlock.add("$<}"); - + private MethodSpec generateToGrpcMethod(Enum anEnum, TypeName protoType) { + CodeBlock switchCases = anEnum.getValues().stream() + .map(value -> CodeBlock.of("case $L -> $T.$L;\n", getNameForValue(value), protoType, value.getName())) + .collect(Poem.joinCodeBlocks()); return MethodSpec.methodBuilder("toGrpc") .addModifiers(Modifier.PUBLIC) .returns(protoType) - .addStatement("return $L", switchBlock.build()) - .build(); + .addStatement(""" + return switch (this) {$> + $L + $<} + """, switchCases + ).build(); } - private MethodSpec generateFromGrpcMethod() { - CodeBlock.Builder switchBlock = CodeBlock.builder().add("switch (grpc) {$>\n"); - for (var value : anEnum.getValues()) { - if (value.isUnused()) { - switchBlock.add("case $L -> throw new $T(\"Enum value $L is marked as unused!\");\n", value.getName(), IllegalArgumentException.class, getNameForValue(value)); - } else { - switchBlock.add("case $L -> $T.$L;\n", value.getName(), generatedType, getNameForValue(value)); - } - } - switchBlock.add("case UNRECOGNIZED -> throw new $T($S);\n", IllegalArgumentException.class, "Enum value is not recognized"); - switchBlock.add("$<}"); + private MethodSpec generateFromGrpcMethod(Enum anEnum, TypeName generatedType, TypeName protoType) { + CodeBlock switchCases = anEnum.getValues().stream() + .map(value -> value.isUnused() + ? CodeBlock.of("case $L -> throw new $T(\"Enum value $L is marked as unused!\");\n", value.getName(), IllegalArgumentException.class, getNameForValue(value)) + : CodeBlock.of("case $L -> $T.$L;\n", value.getName(), generatedType, getNameForValue(value)) + ).collect(Poem.joinCodeBlocks()); + switchCases = switchCases.toBuilder().add("case UNRECOGNIZED -> throw new $T($S);\n", IllegalArgumentException.class, "Enum value is not recognized").build(); return MethodSpec.methodBuilder("fromGrpc") .returns(generatedType) .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .addParameter(ParameterSpec.builder(protoType, "grpc").build()) - .addStatement("return $L", switchBlock.build()) - .build(); + .addStatement(""" + return switch (grpc) {$> + $L + $<} + """, switchCases + ).build(); } } diff --git a/generator/src/main/java/org/sudu/protogen/generator/field/FieldGenerator.java b/generator/src/main/java/org/sudu/protogen/generator/field/FieldGenerator.java index 66a8021..939322a 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/field/FieldGenerator.java +++ b/generator/src/main/java/org/sudu/protogen/generator/field/FieldGenerator.java @@ -3,6 +3,7 @@ import com.squareup.javapoet.FieldSpec; import org.jetbrains.annotations.NotNull; import org.sudu.protogen.descriptors.Field; +import org.sudu.protogen.generator.DescriptorGenerator; import org.sudu.protogen.generator.GenerationContext; import org.sudu.protogen.generator.type.TypeModel; import org.sudu.protogen.utils.Poem; @@ -10,30 +11,28 @@ import java.util.Collection; import java.util.stream.Stream; -public class FieldGenerator { +public class FieldGenerator implements DescriptorGenerator { private final GenerationContext context; - private final Field field; - - public FieldGenerator(GenerationContext context, Field field) { + public FieldGenerator(GenerationContext context) { this.context = context; - this.field = field; } + @Deprecated public static Stream generateSeveral(Collection fields, GenerationContext context) { return fields.stream() - .map(field -> new FieldGenerator(context, field).generate()) + .map(field -> context.generatorsHolder().field(field)) .filter(FieldProcessingResult::isNonVoid); } @NotNull - public FieldProcessingResult generate() { + public FieldProcessingResult generate(Field field) { if (field.isIgnored()) { return FieldProcessingResult.empty(field); } - TypeModel type = context.fieldTypeProcessor().processType(field, context); + TypeModel type = context.typeManager().processType(field); String identifier = field.getGeneratedName(); FieldSpec.Builder fieldSpecBuilder = FieldSpec.builder(type.getTypeName(), identifier); diff --git a/generator/src/main/java/org/sudu/protogen/generator/field/processors/DomainFieldTypeProcessor.java b/generator/src/main/java/org/sudu/protogen/generator/field/processors/DomainFieldTypeProcessor.java index 04283f8..58efeab 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/field/processors/DomainFieldTypeProcessor.java +++ b/generator/src/main/java/org/sudu/protogen/generator/field/processors/DomainFieldTypeProcessor.java @@ -8,19 +8,23 @@ public class DomainFieldTypeProcessor extends FieldTypeProcessor.Chain { + public DomainFieldTypeProcessor(@NotNull GenerationContext context) { + super(context); + } + @Override - public @NotNull TypeModel processType(@NotNull Field field, @NotNull GenerationContext context) { + public @NotNull TypeModel processType(@NotNull Field field) { EnumOrMessage descriptor = switch (field.getType()) { case MESSAGE -> field.getMessageType(); case ENUM -> field.getEnumType(); default -> null; }; if (descriptor != null) { - TypeModel type = context.typeProcessor().processType(descriptor, context.configuration()); + TypeModel type = getContext().typeManager().processType(descriptor); if (type != null) { return type; } } - return next(field, context); + return next(field); } } diff --git a/generator/src/main/java/org/sudu/protogen/generator/field/processors/FieldTypeProcessor.java b/generator/src/main/java/org/sudu/protogen/generator/field/processors/FieldTypeProcessor.java index 74e2e98..0ee0177 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/field/processors/FieldTypeProcessor.java +++ b/generator/src/main/java/org/sudu/protogen/generator/field/processors/FieldTypeProcessor.java @@ -11,20 +11,30 @@ public interface FieldTypeProcessor { @NotNull - TypeModel processType(@NotNull Field field, @NotNull GenerationContext context); + TypeModel processType(@NotNull Field field); abstract class Chain implements FieldTypeProcessor { + private final @NotNull GenerationContext context; + private @Nullable FieldTypeProcessor.Chain next; - public static FieldTypeProcessor getProcessingChain() { + public Chain(@NotNull GenerationContext context) { + this.context = context; + } + + public @NotNull GenerationContext getContext() { + return context; + } + + public static FieldTypeProcessor getProcessingChain(GenerationContext context) { var chain = List.of( // Ordering is important! - new UnfoldedFieldTypeProcessor(), - new MapFieldTypeProcessor(), - new ListFieldTypeProcessor(), - new PrimitiveFieldTypeProcessor(), - new DomainFieldTypeProcessor() + new UnfoldedFieldTypeProcessor(context), + new MapFieldTypeProcessor(context), + new ListFieldTypeProcessor(context), + new PrimitiveFieldTypeProcessor(context), + new DomainFieldTypeProcessor(context) ); for (int i = 0; i < chain.size() - 1; ++i) { var current = chain.get(i); @@ -35,17 +45,17 @@ public static FieldTypeProcessor getProcessingChain() { } @Override - public @NotNull TypeModel processType(@NotNull Field field, @NotNull GenerationContext context) { - return next(field, context); + public @NotNull TypeModel processType(@NotNull Field field) { + return next(field); } private void setNext(@NotNull FieldTypeProcessor.Chain typeProcessor) { this.next = typeProcessor; } - protected final @NotNull TypeModel next(@NotNull Field field, @NotNull GenerationContext context) { + protected final @NotNull TypeModel next(@NotNull Field field) { if (next != null) { - return next.processType(field, context); + return next.processType(field); } throw new IllegalArgumentException("Failed to generate Java type for the field " + field.getName()); } diff --git a/generator/src/main/java/org/sudu/protogen/generator/field/processors/ListFieldTypeProcessor.java b/generator/src/main/java/org/sudu/protogen/generator/field/processors/ListFieldTypeProcessor.java index 6a8efcc..0b3bb9e 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/field/processors/ListFieldTypeProcessor.java +++ b/generator/src/main/java/org/sudu/protogen/generator/field/processors/ListFieldTypeProcessor.java @@ -8,9 +8,13 @@ class ListFieldTypeProcessor extends FieldTypeProcessor.Chain { + public ListFieldTypeProcessor(@NotNull GenerationContext context) { + super(context); + } + @Override - public @NotNull TypeModel processType(@NotNull Field field, @NotNull GenerationContext context) { - TypeModel type = next(field, context); + public @NotNull TypeModel processType(@NotNull Field field) { + TypeModel type = next(field); return field.isList() ? new RepeatedType(type, field.getRepeatedContainer()) : type; diff --git a/generator/src/main/java/org/sudu/protogen/generator/field/processors/MapFieldTypeProcessor.java b/generator/src/main/java/org/sudu/protogen/generator/field/processors/MapFieldTypeProcessor.java index 9c1b9fe..f26f30d 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/field/processors/MapFieldTypeProcessor.java +++ b/generator/src/main/java/org/sudu/protogen/generator/field/processors/MapFieldTypeProcessor.java @@ -9,19 +9,20 @@ class MapFieldTypeProcessor extends FieldTypeProcessor.Chain { + public MapFieldTypeProcessor(@NotNull GenerationContext context) { + super(context); + } + @Override - public @NotNull TypeModel processType(@NotNull Field field, @NotNull GenerationContext context) { + public @NotNull TypeModel processType(@NotNull Field field) { if (!field.isMap()) { - return next(field, context); + return next(field); } Message entryDescriptor = field.getMessageType(); Field key = entryDescriptor.getFields().stream() .filter(f -> f.getName().equals("key")).findFirst().orElseThrow(); Field value = entryDescriptor.getFields().stream() .filter(f -> f.getName().equals("value")).findFirst().orElseThrow(); - return new MapType( - context.fieldTypeProcessor().processType(key, context), - context.fieldTypeProcessor().processType(value, context) - ); + return new MapType(next(key), next(value)); } } diff --git a/generator/src/main/java/org/sudu/protogen/generator/field/processors/PrimitiveFieldTypeProcessor.java b/generator/src/main/java/org/sudu/protogen/generator/field/processors/PrimitiveFieldTypeProcessor.java index 81cb96c..949d6f9 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/field/processors/PrimitiveFieldTypeProcessor.java +++ b/generator/src/main/java/org/sudu/protogen/generator/field/processors/PrimitiveFieldTypeProcessor.java @@ -10,8 +10,12 @@ class PrimitiveFieldTypeProcessor extends FieldTypeProcessor.Chain { + public PrimitiveFieldTypeProcessor(@NotNull GenerationContext context) { + super(context); + } + @Override - public @NotNull TypeModel processType(@NotNull Field field, @NotNull GenerationContext context) { + public @NotNull TypeModel processType(@NotNull Field field) { return switch (field.getType()) { case INT -> boxIfNullable(field, TypeName.INT); case LONG -> boxIfNullable(field, TypeName.LONG); @@ -20,7 +24,7 @@ class PrimitiveFieldTypeProcessor extends FieldTypeProcessor.Chain { case BOOLEAN -> boxIfNullable(field, TypeName.BOOLEAN); case STRING -> boxIfNullable(field, ClassName.get(String.class)); case BYTE_STRING -> new TypeModel(ClassName.get("com.google.protobuf", "ByteString")); - default -> next(field, context); + default -> next(field); }; } diff --git a/generator/src/main/java/org/sudu/protogen/generator/field/processors/UnfoldedFieldTypeProcessor.java b/generator/src/main/java/org/sudu/protogen/generator/field/processors/UnfoldedFieldTypeProcessor.java index ac5c140..1f8c10c 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/field/processors/UnfoldedFieldTypeProcessor.java +++ b/generator/src/main/java/org/sudu/protogen/generator/field/processors/UnfoldedFieldTypeProcessor.java @@ -10,11 +10,15 @@ class UnfoldedFieldTypeProcessor extends FieldTypeProcessor.Chain { + public UnfoldedFieldTypeProcessor(@NotNull GenerationContext context) { + super(context); + } + @Override - public @NotNull TypeModel processType(@NotNull Field field, @NotNull GenerationContext context) { + public @NotNull TypeModel processType(@NotNull Field field) { if (field.isUnfolded()) { Field unfoldedField = field.getUnfoldedField(); - TypeModel unfoldedType = context.fieldTypeProcessor().processType(unfoldedField, context); + TypeModel unfoldedType = getContext().typeManager().processType(unfoldedField); if (unfoldedType instanceof PrimitiveTypeModel primType && field.isNullable()) { unfoldedType = new TypeModel(primType.getTypeName().box()); } @@ -30,6 +34,6 @@ class UnfoldedFieldTypeProcessor extends FieldTypeProcessor.Chain { } return processedModel; } - return next(field, context); + return next(field); } } diff --git a/generator/src/main/java/org/sudu/protogen/generator/message/MessageGenerator.java b/generator/src/main/java/org/sudu/protogen/generator/message/MessageGenerator.java index 69acf67..df4b680 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/message/MessageGenerator.java +++ b/generator/src/main/java/org/sudu/protogen/generator/message/MessageGenerator.java @@ -4,91 +4,105 @@ import org.jetbrains.annotations.NotNull; import org.sudu.protogen.descriptors.EnumOrMessage; import org.sudu.protogen.descriptors.Message; -import org.sudu.protogen.generator.EnumOrMessageGenerator; +import org.sudu.protogen.generator.DescriptorGenerator; import org.sudu.protogen.generator.GenerationContext; -import org.sudu.protogen.generator.field.FieldGenerator; import org.sudu.protogen.generator.field.FieldProcessingResult; import org.sudu.protogen.utils.Poem; import javax.lang.model.element.Modifier; import java.util.List; -public class MessageGenerator { +public class MessageGenerator implements DescriptorGenerator { private final GenerationContext generationContext; - private final Message msgDescriptor; - private final List processedFields; - public MessageGenerator( - @NotNull GenerationContext generationContext, - @NotNull Message msgDescriptor - ) { + public MessageGenerator(@NotNull GenerationContext generationContext) { this.generationContext = generationContext; - this.msgDescriptor = msgDescriptor; - this.processedFields = msgDescriptor.getFields().stream() - .map(field -> new FieldGenerator(generationContext, field).generate()) - .filter(FieldProcessingResult::isNonVoid) - .toList(); } @NotNull - public TypeSpec generate() { - List fields = processedFields.stream() - .map(FieldProcessingResult::field) + public TypeSpec generate(@NotNull Message msgDescriptor) { + TypeSpec.Builder typeBuilder = TypeSpec.recordBuilder(generatedType(msgDescriptor).simpleName()); + + List processedFields = msgDescriptor.getFields().stream() + .map(field -> generationContext.generatorsHolder().field(field)) + .filter(FieldProcessingResult::isNonVoid) .toList(); - List parameters = fields.stream() + addComponents(processedFields, typeBuilder); + implementComparable(msgDescriptor, typeBuilder); + addTopicField(msgDescriptor, typeBuilder); + addTransformingMethods(msgDescriptor, processedFields, typeBuilder); + + return typeBuilder + .multiLineRecord(true) + .addModifiers(Modifier.PUBLIC) + .addTypes(generateNested(msgDescriptor)) + .build(); + } + + private void addComponents(List processedFields, TypeSpec.Builder typeBuilder) { + List parameters = processedFields.stream() + .map(FieldProcessingResult::field) .map(Poem::fieldToParameter) .toList(); - TypeSpec.Builder typeBuilder = TypeSpec.recordBuilder(generatedType().simpleName()) - .addRecordComponents(parameters); + typeBuilder.addRecordComponents(parameters); + } - boolean annotateNotNull = msgDescriptor.getContainingFile().doUseNullabilityAnnotation(false); - msgDescriptor.getComparatorReference().ifPresent( - comparator -> addComparable(typeBuilder, comparator) - ); + private void implementComparable(@NotNull Message msgDescriptor, TypeSpec.Builder typeBuilder) { + msgDescriptor.getComparatorReference().ifPresent(comparator -> { + ClassName type = generatedType(msgDescriptor); + typeBuilder.addSuperinterface(ParameterizedTypeName.get(ClassName.get(Comparable.class), type)); + ParameterSpec methodParameter = ParameterSpec.builder(type, "rhs").build(); + typeBuilder.addMethod( + MethodSpec.methodBuilder("compareTo") + .addModifiers(Modifier.PUBLIC) + .returns(TypeName.INT) + .addParameter(methodParameter) + .addAnnotation(ClassName.get(Override.class)) + .addStatement("return $L.compare(this, $N)", comparator, methodParameter) + .build() + ); + }); + } + private void addTopicField(@NotNull Message msgDescriptor, TypeSpec.Builder typeBuilder) { msgDescriptor.getTopic().ifPresent(topic -> typeBuilder.addField( FieldSpec.builder(ClassName.get(String.class), "TOPIC", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) .initializer(CodeBlock.of("\"$L\"", topic)).build() )); - - return typeBuilder - .multiLineRecord(true) - .addModifiers(Modifier.PUBLIC) - .addTypes(generateNested()) - .addMethod(new FromGrpcMethodGenerator(generationContext, generatedType(), protoType(), processedFields, annotateNotNull).generate()) - .addMethod(new ToGrpcMethodGenerator(generationContext, protoType(), processedFields, annotateNotNull).generate()) - .build(); } - private void addComparable(TypeSpec.Builder typeBuilder, String comparator) { - ClassName type = generatedType(); - typeBuilder.addSuperinterface(ParameterizedTypeName.get(ClassName.get(Comparable.class), type)); - ParameterSpec methodParameter = ParameterSpec.builder(type, "rhs").build(); - typeBuilder.addMethod( - MethodSpec.methodBuilder("compareTo") - .addModifiers(Modifier.PUBLIC) - .returns(TypeName.INT) - .addParameter(methodParameter) - .addAnnotation(ClassName.get(Override.class)) - .addStatement("return $L.compare(this, $N)", comparator, methodParameter) - .build() - ); + private void addTransformingMethods(@NotNull Message msgDescriptor, List processedFields, TypeSpec.Builder typeBuilder) { + boolean annotateNotNull = msgDescriptor.getContainingFile().doUseNullabilityAnnotation(false); + typeBuilder + .addMethod(new FromGrpcMethodGenerator( + generationContext, + generatedType(msgDescriptor), + protoType(msgDescriptor), + processedFields, + annotateNotNull + ).generate()) + .addMethod(new ToGrpcMethodGenerator( + generationContext, + protoType(msgDescriptor), + processedFields, + annotateNotNull + ).generate()); } - private List generateNested() { + private List generateNested(@NotNull Message msgDescriptor) { return msgDescriptor.getNested().stream() .filter(EnumOrMessage::doGenerate) - .map(e -> new EnumOrMessageGenerator(generationContext, e).generate()) + .map(e -> generationContext.generatorsHolder().generate(e)) .toList(); } - private ClassName protoType() { + private ClassName protoType(@NotNull Message msgDescriptor) { return msgDescriptor.getProtobufTypeName(); } - private ClassName generatedType() { + private ClassName generatedType(@NotNull Message msgDescriptor) { return msgDescriptor.getDomainTypeName(generationContext.configuration().namingManager()); } } diff --git a/generator/src/main/java/org/sudu/protogen/generator/server/AbstractServiceMethodGenerator.java b/generator/src/main/java/org/sudu/protogen/generator/server/AbstractServiceMethodGenerator.java index 218a119..48ca851 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/server/AbstractServiceMethodGenerator.java +++ b/generator/src/main/java/org/sudu/protogen/generator/server/AbstractServiceMethodGenerator.java @@ -25,8 +25,8 @@ public class AbstractServiceMethodGenerator { public AbstractServiceMethodGenerator(GenerationContext context, Method method) { this.context = context; this.method = method; - this.requestType = context.processType(method.getInputType()); - this.responseType = context.processType(method.getOutputType()); + this.requestType = context.typeManager().processType(method.getInputType()); + this.responseType = context.typeManager().processType(method.getOutputType()); } public MethodSpec generate() { @@ -56,7 +56,7 @@ private TypeName responseType() { } if (method.doUnfoldResponse(responseType)) { var field = method.unfoldedResponseField(); - return context.processType(field).getTypeName(); + return context.typeManager().processType(field).getTypeName(); } return method.getOutputType().getProtobufTypeName(); } diff --git a/generator/src/main/java/org/sudu/protogen/generator/server/OverriddenServiceMethodGenerator.java b/generator/src/main/java/org/sudu/protogen/generator/server/OverriddenServiceMethodGenerator.java index 5a3519a..d607aba 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/server/OverriddenServiceMethodGenerator.java +++ b/generator/src/main/java/org/sudu/protogen/generator/server/OverriddenServiceMethodGenerator.java @@ -33,8 +33,8 @@ public OverriddenServiceMethodGenerator(GenerationContext context, Method method this.context = context; this.method = method; this.abstractMethodSpec = abstractMethodSpec; - this.requestType = context.processType(method.getInputType()); - this.responseType = context.processType(method.getOutputType()); + this.requestType = context.typeManager().processType(method.getInputType()); + this.responseType = context.typeManager().processType(method.getOutputType()); } public MethodSpec generate() { @@ -52,7 +52,7 @@ private TypeModel responseTypeModel() { return responseType; } if (method.doUnfoldResponse(responseType)) { - return new UnfoldedType(context.processType(method.unfoldedResponseField()), method.getOutputType()); + return new UnfoldedType(context.typeManager().processType(method.unfoldedResponseField()), method.getOutputType()); } return new TypeModel(method.getOutputType().getProtobufTypeName()); } diff --git a/generator/src/main/java/org/sudu/protogen/generator/server/BaseServiceGenerator.java b/generator/src/main/java/org/sudu/protogen/generator/server/ServiceGenerator.java similarity index 75% rename from generator/src/main/java/org/sudu/protogen/generator/server/BaseServiceGenerator.java rename to generator/src/main/java/org/sudu/protogen/generator/server/ServiceGenerator.java index bd1e86b..f58924d 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/server/BaseServiceGenerator.java +++ b/generator/src/main/java/org/sudu/protogen/generator/server/ServiceGenerator.java @@ -3,34 +3,33 @@ import com.squareup.javapoet.*; import org.sudu.protogen.descriptors.Method; import org.sudu.protogen.descriptors.Service; +import org.sudu.protogen.generator.DescriptorGenerator; import org.sudu.protogen.generator.GenerationContext; import javax.annotation.processing.Generated; import javax.lang.model.element.Modifier; import java.util.stream.Stream; -public class BaseServiceGenerator { +public class ServiceGenerator implements DescriptorGenerator { private final GenerationContext context; - private final Service service; - - public BaseServiceGenerator(GenerationContext context, Service service) { + public ServiceGenerator(GenerationContext context) { this.context = context; - this.service = service; } - public TypeSpec generate() { + @Override + public TypeSpec generate(Service service) { TypeSpec.Builder builder = TypeSpec.classBuilder(service.generatedServiceName()) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) - .superclass(protobufStubType()) + .superclass(protobufStubType(service)) .addAnnotation(AnnotationSpec.builder(ClassName.get(Generated.class)).addMember("value", CodeBlock.of("\"protogen\"")).build()) - .addMethods(methods()); + .addMethods(methods(service)); return builder.build(); } - private Iterable methods() { + private Iterable methods(Service service) { return service.getMethods().stream() .filter(Method::doGenerate) .flatMap(method -> { @@ -41,7 +40,7 @@ private Iterable methods() { .toList(); } - private TypeName protobufStubType() { + private TypeName protobufStubType(Service service) { return ClassName.get( service.getContainingFile().getProtoPackage(), service.getName() + "Grpc", diff --git a/generator/src/main/java/org/sudu/protogen/generator/type/processors/DomainTypeProcessor.java b/generator/src/main/java/org/sudu/protogen/generator/type/processors/DomainTypeProcessor.java index 7bf678d..8882222 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/type/processors/DomainTypeProcessor.java +++ b/generator/src/main/java/org/sudu/protogen/generator/type/processors/DomainTypeProcessor.java @@ -2,22 +2,26 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.sudu.protogen.config.Configuration; import org.sudu.protogen.descriptors.EnumOrMessage; +import org.sudu.protogen.generator.GenerationContext; import org.sudu.protogen.generator.type.DomainType; import org.sudu.protogen.generator.type.TypeModel; class DomainTypeProcessor extends TypeProcessor.Chain { + public DomainTypeProcessor(GenerationContext context) { + super(context); + } + @Override - public @Nullable TypeModel processType(@NotNull EnumOrMessage type, @NotNull Configuration configuration) { + public @Nullable TypeModel processType(@NotNull EnumOrMessage type) { if (type.doGenerate() || type.getCustomClass() != null) { - return new DomainType(type.getDomainTypeName(configuration.namingManager())); + return new DomainType(type.getDomainTypeName(getContext().configuration().namingManager())); } // throw new IllegalArgumentException(( // "It's not possible to process type of %s because it doesn't have a domain object. " + // "Specify an existing domain object using custom_class option or generate it." // ).formatted(type.getFullName())); todo move 2 type processor - return next(type, configuration); + return next(type); } } diff --git a/generator/src/main/java/org/sudu/protogen/generator/type/processors/EmptyMessageProcessor.java b/generator/src/main/java/org/sudu/protogen/generator/type/processors/EmptyMessageProcessor.java index c1a7b3c..384b6ac 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/type/processors/EmptyMessageProcessor.java +++ b/generator/src/main/java/org/sudu/protogen/generator/type/processors/EmptyMessageProcessor.java @@ -2,9 +2,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.sudu.protogen.config.Configuration; import org.sudu.protogen.descriptors.EnumOrMessage; import org.sudu.protogen.descriptors.Message; +import org.sudu.protogen.generator.GenerationContext; import org.sudu.protogen.generator.type.TypeModel; import org.sudu.protogen.generator.type.VoidType; @@ -13,11 +13,16 @@ */ public class EmptyMessageProcessor extends TypeProcessor.Chain { + + public EmptyMessageProcessor(GenerationContext context) { + super(context); + } + @Override - public @Nullable TypeModel processType(@NotNull EnumOrMessage descriptor, @NotNull Configuration configuration) { + public @Nullable TypeModel processType(@NotNull EnumOrMessage descriptor) { if (descriptor instanceof Message msg) { if (msg.getFields().isEmpty()) return new VoidType(); } - return next(descriptor, configuration); + return next(descriptor); } } diff --git a/generator/src/main/java/org/sudu/protogen/generator/type/processors/RegisteredTypeProcessor.java b/generator/src/main/java/org/sudu/protogen/generator/type/processors/RegisteredTypeProcessor.java index 09a2591..9b71fe6 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/type/processors/RegisteredTypeProcessor.java +++ b/generator/src/main/java/org/sudu/protogen/generator/type/processors/RegisteredTypeProcessor.java @@ -2,9 +2,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.sudu.protogen.config.Configuration; import org.sudu.protogen.config.RegisteredTransformer; import org.sudu.protogen.descriptors.EnumOrMessage; +import org.sudu.protogen.generator.GenerationContext; import org.sudu.protogen.generator.type.RegisteredType; import org.sudu.protogen.generator.type.TypeModel; @@ -12,9 +12,13 @@ class RegisteredTypeProcessor extends TypeProcessor.Chain { + public RegisteredTypeProcessor(GenerationContext context) { + super(context); + } + @Override - public @Nullable TypeModel processType(@NotNull EnumOrMessage type, @NotNull Configuration configuration) { - List registered = configuration.registeredTransformers(); + public @Nullable TypeModel processType(@NotNull EnumOrMessage type) { + List registered = getContext().configuration().registeredTransformers(); for (var transformer : registered) { if (!type.getFullName().matches(transformer.protoType())) continue; return new RegisteredType( @@ -23,6 +27,6 @@ class RegisteredTypeProcessor extends TypeProcessor.Chain { transformer ); } - return next(type, configuration); + return next(type); } } diff --git a/generator/src/main/java/org/sudu/protogen/generator/type/processors/TypeProcessor.java b/generator/src/main/java/org/sudu/protogen/generator/type/processors/TypeProcessor.java index 64b9bf4..2179190 100644 --- a/generator/src/main/java/org/sudu/protogen/generator/type/processors/TypeProcessor.java +++ b/generator/src/main/java/org/sudu/protogen/generator/type/processors/TypeProcessor.java @@ -2,26 +2,36 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.sudu.protogen.config.Configuration; import org.sudu.protogen.descriptors.EnumOrMessage; +import org.sudu.protogen.generator.GenerationContext; import org.sudu.protogen.generator.type.TypeModel; import java.util.List; public interface TypeProcessor { - @Nullable TypeModel processType(@NotNull EnumOrMessage descriptor, @NotNull Configuration configuration); + @Nullable TypeModel processType(@NotNull EnumOrMessage descriptor); abstract class Chain implements TypeProcessor { + private final GenerationContext context; + private @Nullable Chain next; - public static TypeProcessor getProcessingChain() { + public Chain(GenerationContext context) { + this.context = context; + } + + public GenerationContext getContext() { + return context; + } + + public static TypeProcessor getProcessingChain(GenerationContext context) { var chain = List.of( // Ordering is important! - new RegisteredTypeProcessor(), - new DomainTypeProcessor(), - new EmptyMessageProcessor() + new RegisteredTypeProcessor(context), + new DomainTypeProcessor(context), + new EmptyMessageProcessor(context) ); for (int i = 0; i < chain.size() - 1; ++i) { var current = chain.get(i); @@ -32,17 +42,18 @@ public static TypeProcessor getProcessingChain() { } @Override - public abstract @Nullable TypeModel processType(@NotNull EnumOrMessage descriptor, @NotNull Configuration configuration); - - private void setNext(@NotNull Chain typeProcessor) { - this.next = typeProcessor; - } + public abstract @Nullable TypeModel processType(@NotNull EnumOrMessage descriptor); - protected final @Nullable TypeModel next(@NotNull EnumOrMessage descriptor, @NotNull Configuration configuration) { + protected final @Nullable TypeModel next(@NotNull EnumOrMessage descriptor) { if (next != null) { - return next.processType(descriptor, configuration); + return next.processType(descriptor); } return null; } + + private void setNext(@NotNull Chain typeProcessor) { + this.next = typeProcessor; + } + } } diff --git a/generator/src/main/java/org/sudu/protogen/utils/Poem.java b/generator/src/main/java/org/sudu/protogen/utils/Poem.java index 5718c4f..f307a9c 100644 --- a/generator/src/main/java/org/sudu/protogen/utils/Poem.java +++ b/generator/src/main/java/org/sudu/protogen/utils/Poem.java @@ -4,6 +4,13 @@ import org.jetbrains.annotations.NotNull; import org.sudu.protogen.generator.GenerationContext; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; + public class Poem { @NotNull @@ -53,4 +60,33 @@ public static void attachNullabilityAnnotations( builder.addAnnotation(context.configuration().nonnullAnnotationClass()); } } + + public static Collector joinCodeBlocks() { + return new Collector<>() { + @Override + public Supplier supplier() { + return CodeBlock::builder; + } + + @Override + public BiConsumer accumulator() { + return CodeBlock.Builder::add; + } + + @Override + public BinaryOperator combiner() { + return (builder1, builder2) -> builder1.add(builder2.build()); + } + + @Override + public Function finisher() { + return CodeBlock.Builder::build; + } + + @Override + public Set characteristics() { + return Set.of(); + } + }; + } }