diff --git a/generators/java/generator-utils/src/main/java/com/fern/java/generators/ObjectGenerator.java b/generators/java/generator-utils/src/main/java/com/fern/java/generators/ObjectGenerator.java index 727cef09234..55bac7cca5e 100644 --- a/generators/java/generator-utils/src/main/java/com/fern/java/generators/ObjectGenerator.java +++ b/generators/java/generator-utils/src/main/java/com/fern/java/generators/ObjectGenerator.java @@ -15,111 +15,35 @@ */ package com.fern.java.generators; -import com.fern.ir.model.commons.TypeId; -import com.fern.ir.model.types.DeclaredTypeName; import com.fern.ir.model.types.ObjectProperty; -import com.fern.ir.model.types.ObjectTypeDeclaration; import com.fern.java.AbstractGeneratorContext; -import com.fern.java.PoetTypeNameMapper; import com.fern.java.generators.object.EnrichedObjectProperty; -import com.fern.java.generators.object.ImplementsInterface; -import com.fern.java.generators.object.ObjectTypeSpecGenerator; -import com.fern.java.output.GeneratedJavaInterface; import com.fern.java.output.GeneratedObject; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.TypeSpec; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Optional; -import java.util.Queue; -import java.util.Set; -import java.util.stream.Collectors; public final class ObjectGenerator extends AbstractFileGenerator { - private final ObjectTypeDeclaration objectTypeDeclaration; - private final Optional selfInterface; - private final Map allGeneratedInterfaces; - private final List extendedInterfaces = new ArrayList<>(); + private final TypeSpec objectTypeSpec; + private final Map objectPropertyGetters; + private final List extendedPropertyGetters; public ObjectGenerator( - ObjectTypeDeclaration objectTypeDeclaration, - Optional selfInterface, - List extendedInterfaces, AbstractGeneratorContext generatorContext, - Map allGeneratedInterfaces, - ClassName className) { + ClassName className, + TypeSpec objectTypeSpec, + Map objectPropertyGetters, + List extendedPropertyGetters) { super(className, generatorContext); - this.objectTypeDeclaration = objectTypeDeclaration; - this.selfInterface = selfInterface; - selfInterface.ifPresent(this.extendedInterfaces::add); - this.extendedInterfaces.addAll(extendedInterfaces); - this.allGeneratedInterfaces = allGeneratedInterfaces; + this.objectTypeSpec = objectTypeSpec; + this.objectPropertyGetters = objectPropertyGetters; + this.extendedPropertyGetters = extendedPropertyGetters; } @Override public GeneratedObject generateFile() { - PoetTypeNameMapper poetTypeNameMapper = generatorContext.getPoetTypeNameMapper(); - List enrichedObjectProperties = new ArrayList<>(); - Map objectPropertyGetters = new HashMap<>(); - List extendedPropertyGetters = new ArrayList<>(); - if (selfInterface.isEmpty()) { - enrichedObjectProperties = objectTypeDeclaration.getProperties().stream() - .map(objectProperty -> { - EnrichedObjectProperty enrichedObjectProperty = EnrichedObjectProperty.of( - objectProperty, - false, - poetTypeNameMapper.convertToTypeName(true, objectProperty.getValueType())); - objectPropertyGetters.put(objectProperty, enrichedObjectProperty); - return enrichedObjectProperty; - }) - .collect(Collectors.toList()); - } - List implementsInterfaces = new ArrayList<>(); - Set visited = new HashSet<>(); - extendedInterfaces.stream() - .map(generatedInterface -> { - List enrichedProperties = new ArrayList<>(); - Queue interfaceQueue = new LinkedList<>(); - interfaceQueue.add(generatedInterface); - while (!interfaceQueue.isEmpty()) { - GeneratedJavaInterface generatedJavaInterface = interfaceQueue.poll(); - if (visited.contains(generatedJavaInterface)) { - continue; - } - interfaceQueue.addAll(generatedJavaInterface.extendedInterfaces().stream() - .map(DeclaredTypeName::getTypeId) - .map(allGeneratedInterfaces::get) - .collect(Collectors.toList())); - enrichedProperties.addAll( - getEnrichedObjectProperties(generatedJavaInterface, objectPropertyGetters)); - visited.add(generatedJavaInterface); - } - return ImplementsInterface.builder() - .interfaceClassName(generatedInterface.getClassName()) - .addAllInterfaceProperties(enrichedProperties) - .build(); - }) - .forEach(implementsInterface -> { - extendedPropertyGetters.addAll(implementsInterface.interfaceProperties()); - implementsInterfaces.add(implementsInterface); - }); - ObjectTypeSpecGenerator genericObjectGenerator = new ObjectTypeSpecGenerator( - className, - generatorContext.getPoetClassNameFactory().getObjectMapperClassName(), - enrichedObjectProperties, - implementsInterfaces, - true, - generatorContext.getCustomConfig().enablePublicConstructors(), - generatorContext.deserializeWithAdditionalProperties(), - generatorContext.getCustomConfig().jsonInclude(), - generatorContext.getCustomConfig().disableRequiredPropertyBuilderChecks(), - generatorContext.builderNotNullChecks()); - TypeSpec objectTypeSpec = genericObjectGenerator.generate(); JavaFile javaFile = JavaFile.builder(className.packageName(), objectTypeSpec).build(); return GeneratedObject.builder() @@ -129,17 +53,4 @@ public GeneratedObject generateFile() { .addAllExtendedObjectPropertyGetters(extendedPropertyGetters) .build(); } - - private static List getEnrichedObjectProperties( - GeneratedJavaInterface generatedJavaInterface, - Map objectPropertyGetters) { - return generatedJavaInterface.propertyMethodSpecs().stream() - .map(propertyMethodSpec -> { - EnrichedObjectProperty enrichedObjectProperty = EnrichedObjectProperty.of( - propertyMethodSpec.objectProperty(), true, propertyMethodSpec.methodSpec().returnType); - objectPropertyGetters.put(propertyMethodSpec.objectProperty(), enrichedObjectProperty); - return enrichedObjectProperty; - }) - .collect(Collectors.toList()); - } } diff --git a/generators/java/generator-utils/src/main/java/com/fern/java/generators/SingleTypeGenerator.java b/generators/java/generator-utils/src/main/java/com/fern/java/generators/SingleTypeGenerator.java index 24ab1610cde..4d67d4ee487 100644 --- a/generators/java/generator-utils/src/main/java/com/fern/java/generators/SingleTypeGenerator.java +++ b/generators/java/generator-utils/src/main/java/com/fern/java/generators/SingleTypeGenerator.java @@ -9,6 +9,7 @@ import com.fern.ir.model.types.UndiscriminatedUnionTypeDeclaration; import com.fern.ir.model.types.UnionTypeDeclaration; import com.fern.java.AbstractGeneratorContext; +import com.fern.java.generators.object.ObjectTypeSpecGenerator; import com.fern.java.output.GeneratedJavaFile; import com.fern.java.output.GeneratedJavaInterface; import com.fern.java.output.GeneratedObject; @@ -25,6 +26,7 @@ public final class SingleTypeGenerator implements Type.Visitor allGeneratedInterfaces; private final boolean fromErrorDeclaration; + private final SingleTypeSpecGenerator typeSpecGenerator; public SingleTypeGenerator( AbstractGeneratorContext generatorContext, @@ -37,6 +39,8 @@ public SingleTypeGenerator( this.allGeneratedInterfaces = allGeneratedInterfaces; this.declaredTypeName = declaredTypeName; this.fromErrorDeclaration = fromErrorDeclaration; + this.typeSpecGenerator = new SingleTypeSpecGenerator( + generatorContext, declaredTypeName, className, allGeneratedInterfaces, fromErrorDeclaration); } @Override @@ -60,13 +64,19 @@ public Optional visitObject(ObjectTypeDeclaration value) { .map(DeclaredTypeName::getTypeId) .map(allGeneratedInterfaces::get) .collect(Collectors.toList()); - ObjectGenerator objectGenerator = new ObjectGenerator( + ObjectTypeSpecGenerator objectTypeSpecGenerator = new ObjectTypeSpecGenerator( value, Optional.ofNullable(allGeneratedInterfaces.get(declaredTypeName.getTypeId())), extendedInterfaces, generatorContext, allGeneratedInterfaces, className); + ObjectGenerator objectGenerator = new ObjectGenerator( + generatorContext, + className, + objectTypeSpecGenerator.generate(), + objectTypeSpecGenerator.objectPropertyGetters(), + objectTypeSpecGenerator.extendedPropertyGetters()); GeneratedObject generatedObject = objectGenerator.generateFile(); return Optional.of(GeneratedJavaFile.builder() .className(generatedObject.getClassName()) diff --git a/generators/java/generator-utils/src/main/java/com/fern/java/generators/SingleTypeSpecGenerator.java b/generators/java/generator-utils/src/main/java/com/fern/java/generators/SingleTypeSpecGenerator.java new file mode 100644 index 00000000000..021207648f3 --- /dev/null +++ b/generators/java/generator-utils/src/main/java/com/fern/java/generators/SingleTypeSpecGenerator.java @@ -0,0 +1,82 @@ +package com.fern.java.generators; + +import com.fern.ir.model.commons.TypeId; +import com.fern.ir.model.types.AliasTypeDeclaration; +import com.fern.ir.model.types.DeclaredTypeName; +import com.fern.ir.model.types.EnumTypeDeclaration; +import com.fern.ir.model.types.ObjectTypeDeclaration; +import com.fern.ir.model.types.Type; +import com.fern.ir.model.types.UndiscriminatedUnionTypeDeclaration; +import com.fern.ir.model.types.UnionTypeDeclaration; +import com.fern.java.AbstractGeneratorContext; +import com.fern.java.generators.object.ObjectTypeSpecGenerator; +import com.fern.java.output.GeneratedJavaInterface; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.TypeSpec; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +public class SingleTypeSpecGenerator implements Type.Visitor> { + + private final AbstractGeneratorContext generatorContext; + private final DeclaredTypeName declaredTypeName; + private final ClassName className; + private final Map allGeneratedInterfaces; + private final boolean fromErrorDeclaration; + + public SingleTypeSpecGenerator( + AbstractGeneratorContext generatorContext, + DeclaredTypeName declaredTypeName, + ClassName className, + Map allGeneratedInterfaces, + boolean fromErrorDeclaration) { + this.generatorContext = generatorContext; + this.className = className; + this.allGeneratedInterfaces = allGeneratedInterfaces; + this.declaredTypeName = declaredTypeName; + this.fromErrorDeclaration = fromErrorDeclaration; + } + + @Override + public Optional visitAlias(AliasTypeDeclaration value) { + return Optional.empty(); + } + + @Override + public Optional visitEnum(EnumTypeDeclaration value) { + return Optional.empty(); + } + + @Override + public Optional visitObject(ObjectTypeDeclaration value) { + List extendedInterfaces = value.getExtends().stream() + .map(DeclaredTypeName::getTypeId) + .map(allGeneratedInterfaces::get) + .collect(Collectors.toList()); + ObjectTypeSpecGenerator objectTypeSpecGenerator = new ObjectTypeSpecGenerator( + value, + Optional.ofNullable(allGeneratedInterfaces.get(declaredTypeName.getTypeId())), + extendedInterfaces, + generatorContext, + allGeneratedInterfaces, + className); + return Optional.of(objectTypeSpecGenerator.generate()); + } + + @Override + public Optional visitUnion(UnionTypeDeclaration value) { + return Optional.empty(); + } + + @Override + public Optional visitUndiscriminatedUnion(UndiscriminatedUnionTypeDeclaration undiscriminatedUnion) { + return Optional.empty(); + } + + @Override + public Optional _visitUnknown(Object o) { + return Optional.empty(); + } +} diff --git a/generators/java/generator-utils/src/main/java/com/fern/java/generators/object/ObjectTypeSpecGenerator.java b/generators/java/generator-utils/src/main/java/com/fern/java/generators/object/ObjectTypeSpecGenerator.java index 327001b56c6..96b5a8ed66f 100644 --- a/generators/java/generator-utils/src/main/java/com/fern/java/generators/object/ObjectTypeSpecGenerator.java +++ b/generators/java/generator-utils/src/main/java/com/fern/java/generators/object/ObjectTypeSpecGenerator.java @@ -3,11 +3,18 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fern.ir.model.commons.TypeId; +import com.fern.ir.model.types.DeclaredTypeName; +import com.fern.ir.model.types.ObjectProperty; +import com.fern.ir.model.types.ObjectTypeDeclaration; +import com.fern.java.AbstractGeneratorContext; import com.fern.java.ICustomConfig; import com.fern.java.ObjectMethodFactory; import com.fern.java.ObjectMethodFactory.EqualsMethod; +import com.fern.java.PoetTypeNameMapper; import com.fern.java.PoetTypeWithClassName; import com.fern.java.generators.ObjectMappersGenerator; +import com.fern.java.output.GeneratedJavaInterface; import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.FieldSpec; @@ -16,9 +23,14 @@ import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeSpec; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Queue; +import java.util.Set; import java.util.stream.Collectors; import javax.lang.model.element.Modifier; @@ -33,31 +45,83 @@ public final class ObjectTypeSpecGenerator { private final boolean supportAdditionalProperties; private final boolean disableRequiredPropertyBuilderChecks; private final boolean builderNotNullChecks; + private final Map objectPropertyGetters = new HashMap<>(); + private final List extendedPropertyGetters = new ArrayList<>(); public ObjectTypeSpecGenerator( - ClassName objectClassName, - ClassName generatedObjectMapperClassName, - List enrichedObjectProperties, - List interfaces, - boolean isSerialized, - boolean publicConstructorsEnabled, - boolean supportAdditionalProperties, - ICustomConfig.JsonInclude jsonInclude, - Boolean disableRequiredPropertyBuilderChecks, - boolean builderNotNullChecks) { - this.objectClassName = objectClassName; - this.generatedObjectMapperClassName = generatedObjectMapperClassName; - this.interfaces = interfaces; - this.jsonInclude = jsonInclude; - this.builderNotNullChecks = builderNotNullChecks; + ObjectTypeDeclaration objectTypeDeclaration, + Optional selfInterface, + List extendedInterfaces, + AbstractGeneratorContext generatorContext, + Map allGeneratedInterfaces, + ClassName className) { + selfInterface.ifPresent(extendedInterfaces::add); + PoetTypeNameMapper poetTypeNameMapper = generatorContext.getPoetTypeNameMapper(); + List enrichedObjectProperties = new ArrayList<>(); + if (selfInterface.isEmpty()) { + enrichedObjectProperties = objectTypeDeclaration.getProperties().stream() + .map(objectProperty -> { + EnrichedObjectProperty enrichedObjectProperty = EnrichedObjectProperty.of( + objectProperty, + false, + poetTypeNameMapper.convertToTypeName(true, objectProperty.getValueType())); + this.objectPropertyGetters.put(objectProperty, enrichedObjectProperty); + return enrichedObjectProperty; + }) + .collect(Collectors.toList()); + } + List implementsInterfaces = new ArrayList<>(); + Set visited = new HashSet<>(); + extendedInterfaces.stream() + .map(generatedInterface -> { + List enrichedProperties = new ArrayList<>(); + Queue interfaceQueue = new LinkedList<>(); + interfaceQueue.add(generatedInterface); + while (!interfaceQueue.isEmpty()) { + GeneratedJavaInterface generatedJavaInterface = interfaceQueue.poll(); + if (visited.contains(generatedJavaInterface)) { + continue; + } + interfaceQueue.addAll(generatedJavaInterface.extendedInterfaces().stream() + .map(DeclaredTypeName::getTypeId) + .map(allGeneratedInterfaces::get) + .collect(Collectors.toList())); + enrichedProperties.addAll( + getEnrichedObjectProperties(generatedJavaInterface, objectPropertyGetters)); + visited.add(generatedJavaInterface); + } + return ImplementsInterface.builder() + .interfaceClassName(generatedInterface.getClassName()) + .addAllInterfaceProperties(enrichedProperties) + .build(); + }) + .forEach(implementsInterface -> { + this.extendedPropertyGetters.addAll(implementsInterface.interfaceProperties()); + implementsInterfaces.add(implementsInterface); + }); + this.objectClassName = className; + this.generatedObjectMapperClassName = + generatorContext.getPoetClassNameFactory().getObjectMapperClassName(); + this.interfaces = implementsInterfaces; + this.jsonInclude = generatorContext.getCustomConfig().jsonInclude(); + this.builderNotNullChecks = generatorContext.builderNotNullChecks(); for (ImplementsInterface implementsInterface : interfaces) { allEnrichedProperties.addAll(implementsInterface.interfaceProperties()); } allEnrichedProperties.addAll(enrichedObjectProperties); - this.isSerialized = isSerialized; - this.publicConstructorsEnabled = publicConstructorsEnabled; - this.supportAdditionalProperties = supportAdditionalProperties; - this.disableRequiredPropertyBuilderChecks = disableRequiredPropertyBuilderChecks; + this.isSerialized = true; + this.publicConstructorsEnabled = generatorContext.getCustomConfig().enablePublicConstructors(); + this.supportAdditionalProperties = generatorContext.deserializeWithAdditionalProperties(); + this.disableRequiredPropertyBuilderChecks = + generatorContext.getCustomConfig().disableRequiredPropertyBuilderChecks(); + } + + public Map objectPropertyGetters() { + return this.objectPropertyGetters; + } + + public List extendedPropertyGetters() { + return this.extendedPropertyGetters; } public TypeSpec generate() { @@ -206,4 +270,17 @@ private Optional generateBuilder() { builderNotNullChecks); return builderGenerator.generate(); } + + private static List getEnrichedObjectProperties( + GeneratedJavaInterface generatedJavaInterface, + Map objectPropertyGetters) { + return generatedJavaInterface.propertyMethodSpecs().stream() + .map(propertyMethodSpec -> { + EnrichedObjectProperty enrichedObjectProperty = EnrichedObjectProperty.of( + propertyMethodSpec.objectProperty(), true, propertyMethodSpec.methodSpec().returnType); + objectPropertyGetters.put(propertyMethodSpec.objectProperty(), enrichedObjectProperty); + return enrichedObjectProperty; + }) + .collect(Collectors.toList()); + } } diff --git a/generators/java/sdk/src/main/java/com/fern/java/client/generators/WrappedRequestGenerator.java b/generators/java/sdk/src/main/java/com/fern/java/client/generators/WrappedRequestGenerator.java index 5fe111a7375..898ef496c05 100644 --- a/generators/java/sdk/src/main/java/com/fern/java/client/generators/WrappedRequestGenerator.java +++ b/generators/java/sdk/src/main/java/com/fern/java/client/generators/WrappedRequestGenerator.java @@ -39,6 +39,7 @@ import com.fern.java.client.GeneratedWrappedRequest.RequestBodyGetter; import com.fern.java.generators.AbstractFileGenerator; import com.fern.java.generators.ObjectGenerator; +import com.fern.java.generators.object.ObjectTypeSpecGenerator; import com.fern.java.output.GeneratedJavaInterface; import com.fern.java.output.GeneratedObject; import com.squareup.javapoet.ClassName; @@ -146,7 +147,7 @@ public GeneratedWrappedRequest generateFile() { .addAllProperties(queryParameterObjectProperties) .addAllProperties(objectProperties) .build(); - ObjectGenerator objectGenerator = new ObjectGenerator( + ObjectTypeSpecGenerator objectTypeSpecGenerator = new ObjectTypeSpecGenerator( objectTypeDeclaration, Optional.empty(), extendedInterfaces.stream() @@ -156,6 +157,12 @@ public GeneratedWrappedRequest generateFile() { generatorContext, allGeneratedInterfaces, className); + ObjectGenerator objectGenerator = new ObjectGenerator( + generatorContext, + className, + objectTypeSpecGenerator.generate(), + objectTypeSpecGenerator.objectPropertyGetters(), + objectTypeSpecGenerator.extendedPropertyGetters()); GeneratedObject generatedObject = objectGenerator.generateFile(); RequestBodyGetterFactory requestBodyGetterFactory = new RequestBodyGetterFactory(objectProperties, generatedObject); diff --git a/generators/java/spring/src/main/java/com/fern/java/spring/generators/InlinedRequestBodyGenerator.java b/generators/java/spring/src/main/java/com/fern/java/spring/generators/InlinedRequestBodyGenerator.java index 891bb58824a..e8971b4e175 100644 --- a/generators/java/spring/src/main/java/com/fern/java/spring/generators/InlinedRequestBodyGenerator.java +++ b/generators/java/spring/src/main/java/com/fern/java/spring/generators/InlinedRequestBodyGenerator.java @@ -24,6 +24,7 @@ import com.fern.java.RequestBodyUtils; import com.fern.java.generators.AbstractFileGenerator; import com.fern.java.generators.ObjectGenerator; +import com.fern.java.generators.object.ObjectTypeSpecGenerator; import com.fern.java.output.AbstractGeneratedJavaFile; import com.fern.java.output.GeneratedJavaInterface; import com.fern.java.spring.SpringGeneratorContext; @@ -63,13 +64,19 @@ public AbstractGeneratedJavaFile generateFile() { .addAllExtends(inlinedRequestBody.getExtends()) .addAllProperties(RequestBodyUtils.convertToObjectProperties(inlinedRequestBody)) .build(); - ObjectGenerator objectGenerator = new ObjectGenerator( + ObjectTypeSpecGenerator objectTypeSpecGenerator = new ObjectTypeSpecGenerator( objectTypeDeclaration, Optional.empty(), extendedInterfaces, generatorContext, allGeneratedInterfaces, className); + ObjectGenerator objectGenerator = new ObjectGenerator( + generatorContext, + className, + objectTypeSpecGenerator.generate(), + objectTypeSpecGenerator.objectPropertyGetters(), + objectTypeSpecGenerator.extendedPropertyGetters()); return objectGenerator.generateFile(); } }