Skip to content

Commit

Permalink
Make generator non descriptor-specific
Browse files Browse the repository at this point in the history
  • Loading branch information
Duzhinsky committed Oct 5, 2023
1 parent 64bb360 commit 796c264
Show file tree
Hide file tree
Showing 33 changed files with 406 additions and 238 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package org.sudu.protogen.descriptors;

public interface Descriptor {
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.sudu.protogen.generator;

import org.sudu.protogen.descriptors.Descriptor;

import java.util.WeakHashMap;

public interface DescriptorGenerator<D extends Descriptor, T> {

T generate(D descriptor);

default DescriptorGenerator<D, T> withCache() {
return new CachedGenerator<>(this);
}

class CachedGenerator<D extends Descriptor, T> implements DescriptorGenerator<D, T> {

private final WeakHashMap<D, T> cache;

private final DescriptorGenerator<D, T> generator;

public CachedGenerator(DescriptorGenerator<D, T> generator, WeakHashMap<D, T> cache) {
this.cache = cache;
this.generator = generator;
}

public CachedGenerator(DescriptorGenerator<D, T> generator) {
this(generator, new WeakHashMap<>());
}

public final T generate(D descriptor) {
return cache.computeIfAbsent(descriptor, generator::generate);
}
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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<Field, FieldProcessingResult> fieldGenerator = new FieldGenerator(GenerationContext.this).withCache();
private final DescriptorGenerator<Message, TypeSpec> messageGenerator = new MessageGenerator(GenerationContext.this).withCache();
private final DescriptorGenerator<Enum, TypeSpec> enumGenerator = new EnumGenerator(GenerationContext.this).withCache();
private final DescriptorGenerator<Service, TypeSpec> clientGenerator = new ClientGenerator(GenerationContext.this).withCache();
private final DescriptorGenerator<Service, TypeSpec> 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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -50,7 +48,7 @@ private List<JavaFile> 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()
);
Expand All @@ -59,11 +57,11 @@ private List<JavaFile> 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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ private CodeBlock buildRequest(List<ParameterSpec> params) {
@NotNull
private CodeBlock buildNonDomainRequest(ClassName requestProtoType) {
List<FieldProcessingResult> 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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -14,7 +15,7 @@
import java.util.List;
import java.util.stream.Stream;

public class ClientGenerator {
public class ClientGenerator implements DescriptorGenerator<Service, TypeSpec> {

public static final String modificationNotice = """
The client was generated by protogen. If you want to add some logic, mark the service using
Expand All @@ -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()) {
Expand All @@ -55,7 +51,7 @@ public TypeSpec generate() {
return builder.build();
}

private List<MethodSpec> generateConstructors() {
private List<MethodSpec> generateConstructors(Service service) {
return List.of(
MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
Expand All @@ -70,21 +66,21 @@ private List<MethodSpec> generateConstructors() {
);
}

private Stream<MethodSpec> generateRpcMethod(Method method) {
private Stream<MethodSpec> 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 {
Expand Down
Loading

0 comments on commit 796c264

Please sign in to comment.