diff --git a/generators/java/generator-utils/src/main/java/com/fern/java/generators/InterfaceGenerator.java b/generators/java/generator-utils/src/main/java/com/fern/java/generators/InterfaceGenerator.java index afd24698645..0de10d17e9d 100644 --- a/generators/java/generator-utils/src/main/java/com/fern/java/generators/InterfaceGenerator.java +++ b/generators/java/generator-utils/src/main/java/com/fern/java/generators/InterfaceGenerator.java @@ -20,6 +20,7 @@ import com.fern.java.AbstractGeneratorContext; import com.fern.java.output.GeneratedJavaInterface; import com.fern.java.output.GeneratedJavaInterface.PropertyMethodSpec; +import com.fern.java.utils.TypeReferenceInlineChecker; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; @@ -44,6 +45,7 @@ public InterfaceGenerator( @Override public GeneratedJavaInterface generateFile() { List methodSpecsByProperties = getPropertyGetters(); + List renderedSpecsByProperties = getRenderedPropertyGetters(); List superInterfaces = objectTypeDeclaration.getExtends().stream() .map(declaredTypeName -> generatorContext.getPoetClassNameFactory().getInterfaceClassName(declaredTypeName)) @@ -51,7 +53,7 @@ public GeneratedJavaInterface generateFile() { TypeSpec interfaceTypeSpec = TypeSpec.interfaceBuilder(className) .addModifiers(Modifier.PUBLIC) .addSuperinterfaces(superInterfaces) - .addMethods(methodSpecsByProperties.stream() + .addMethods(renderedSpecsByProperties.stream() .map(PropertyMethodSpec::methodSpec) .collect(Collectors.toList())) .build(); @@ -87,4 +89,34 @@ private List getPropertyGetters() { }) .collect(Collectors.toList()); } + + private List getRenderedPropertyGetters() { + return objectTypeDeclaration.getProperties().stream() + // Omit any types we're going to inline + .filter(objectProperty -> { + if (!generatorContext.getCustomConfig().enableInlineTypes()) { + return true; + } + return !objectProperty.getValueType().visit(new TypeReferenceInlineChecker(generatorContext)); + }) + .map(objectProperty -> { + TypeName poetTypeName = generatorContext + .getPoetTypeNameMapper() + .convertToTypeName(true, objectProperty.getValueType()); + MethodSpec getter = MethodSpec.methodBuilder("get" + + objectProperty + .getName() + .getName() + .getPascalCase() + .getSafeName()) + .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) + .returns(poetTypeName) + .build(); + return PropertyMethodSpec.builder() + .objectProperty(objectProperty) + .methodSpec(getter) + .build(); + }) + .collect(Collectors.toList()); + } } 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 2f7602b2fbf..ef24c347a72 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 @@ -30,6 +30,7 @@ import com.fern.java.output.GeneratedObject; import com.fern.java.utils.InlineTypeIdResolver; import com.fern.java.utils.NamedTypeId; +import com.fern.java.utils.TypeReferenceInlineChecker; import com.google.common.collect.ImmutableMap; import com.palantir.common.streams.KeyedStream; import com.squareup.javapoet.ClassName; @@ -71,8 +72,8 @@ public ObjectGenerator( getUniqueAncestorsInLevelOrder(allExtendedInterfaces, allGeneratedInterfaces); List enriched = enrichedObjectProperties( - selfInterface, objectTypeDeclaration, generatorContext.getPoetTypeNameMapper()); - List implemented = implementsInterfaces(ancestors); + generatorContext, selfInterface, objectTypeDeclaration, generatorContext.getPoetTypeNameMapper()); + List implemented = implementsInterfaces(generatorContext, ancestors); if (generatorContext.getCustomConfig().enableInlineTypes()) { List allEnrichedProperties = new ArrayList<>(); @@ -240,12 +241,13 @@ private static Map overridePrope for (EnrichedObjectProperty prop : enrichedObjectProperties) { TypeName typeName = overriddenMapper.convertToTypeName( - false, prop.objectProperty().getValueType()); + true, prop.objectProperty().getValueType()); EnrichedObjectProperty overridden = EnrichedObjectProperty.builder() .camelCaseKey(prop.camelCaseKey()) .pascalCaseKey(prop.pascalCaseKey()) .poetTypeName(typeName) .fromInterface(prop.fromInterface()) + .inline(true) .objectProperty(prop.objectProperty()) .wireKey(prop.wireKey()) .docs(prop.docs()) @@ -257,35 +259,51 @@ private static Map overridePrope return result; } - private static List implementsInterfaces(List ancestors) { + private static List implementsInterfaces( + AbstractGeneratorContext generatorContext, List ancestors) { return ancestors.stream() .map(generatedInterface -> ImplementsInterface.builder() .interfaceClassName(generatedInterface.getClassName()) - .addAllInterfaceProperties(getEnrichedObjectProperties(generatedInterface)) + .addAllInterfaceProperties(getEnrichedObjectProperties(generatorContext, generatedInterface)) .build()) .collect(Collectors.toList()); } private static List enrichedObjectProperties( + AbstractGeneratorContext generatorContext, Optional selfInterface, ObjectTypeDeclaration objectTypeDeclaration, PoetTypeNameMapper poetTypeNameMapper) { if (selfInterface.isEmpty()) { return objectTypeDeclaration.getProperties().stream() - .map(objectProperty -> EnrichedObjectProperty.of( - objectProperty, - false, - poetTypeNameMapper.convertToTypeName(true, objectProperty.getValueType()))) + .map(objectProperty -> { + boolean inline = + objectProperty.getValueType().visit(new TypeReferenceInlineChecker(generatorContext)); + return EnrichedObjectProperty.of( + objectProperty, + false, + inline, + poetTypeNameMapper.convertToTypeName(true, objectProperty.getValueType())); + }) .collect(Collectors.toList()); } return List.of(); } private static List getEnrichedObjectProperties( - GeneratedJavaInterface generatedJavaInterface) { + AbstractGeneratorContext generatorContext, GeneratedJavaInterface generatedJavaInterface) { return generatedJavaInterface.propertyMethodSpecs().stream() - .map(propertyMethodSpec -> EnrichedObjectProperty.of( - propertyMethodSpec.objectProperty(), true, propertyMethodSpec.methodSpec().returnType)) + .map(propertyMethodSpec -> { + boolean inline = propertyMethodSpec + .objectProperty() + .getValueType() + .visit(new TypeReferenceInlineChecker(generatorContext)); + return EnrichedObjectProperty.of( + propertyMethodSpec.objectProperty(), + true, + inline, + propertyMethodSpec.methodSpec().returnType); + }) .collect(Collectors.toList()); } diff --git a/generators/java/generator-utils/src/main/java/com/fern/java/generators/UndiscriminatedUnionGenerator.java b/generators/java/generator-utils/src/main/java/com/fern/java/generators/UndiscriminatedUnionGenerator.java index 38f89219bc6..0c9f1d70879 100644 --- a/generators/java/generator-utils/src/main/java/com/fern/java/generators/UndiscriminatedUnionGenerator.java +++ b/generators/java/generator-utils/src/main/java/com/fern/java/generators/UndiscriminatedUnionGenerator.java @@ -239,7 +239,7 @@ private static Map overrideMemberTypeNames mapperEnclosingClasses); for (UndiscriminatedUnionMember member : undiscriminatedUnion.getMembers()) { - TypeName typeName = overriddenMapper.convertToTypeName(false, member.getType()); + TypeName typeName = overriddenMapper.convertToTypeName(true, member.getType()); result.put(member, typeName); } diff --git a/generators/java/generator-utils/src/main/java/com/fern/java/generators/object/EnrichedObjectProperty.java b/generators/java/generator-utils/src/main/java/com/fern/java/generators/object/EnrichedObjectProperty.java index a2843d3070a..646753660c7 100644 --- a/generators/java/generator-utils/src/main/java/com/fern/java/generators/object/EnrichedObjectProperty.java +++ b/generators/java/generator-utils/src/main/java/com/fern/java/generators/object/EnrichedObjectProperty.java @@ -31,6 +31,8 @@ public interface EnrichedObjectProperty { boolean fromInterface(); + boolean inline(); + Optional docs(); Optional literal(); @@ -83,7 +85,7 @@ public Void _visitUnknown(Object unknownType) { .addMember("value", "$S", wireKey().get()) .build()); } - if (fromInterface()) { + if (fromInterface() && !inline()) { getterBuilder.addAnnotation(ClassName.get("", "java.lang.Override")); } if (docs().isPresent()) { @@ -96,7 +98,8 @@ static ImmutableEnrichedObjectProperty.CamelCaseKeyBuildStage builder() { return ImmutableEnrichedObjectProperty.builder(); } - static EnrichedObjectProperty of(ObjectProperty objectProperty, boolean fromInterface, TypeName poetTypeName) { + static EnrichedObjectProperty of( + ObjectProperty objectProperty, boolean fromInterface, boolean inline, TypeName poetTypeName) { Name name = objectProperty.getName().getName(); Optional maybeLiteral = objectProperty.getValueType().getContainer().flatMap(ContainerType::getLiteral); @@ -105,6 +108,7 @@ static EnrichedObjectProperty of(ObjectProperty objectProperty, boolean fromInte .pascalCaseKey(name.getPascalCase().getSafeName()) .poetTypeName(poetTypeName) .fromInterface(fromInterface) + .inline(inline) .objectProperty(objectProperty) .wireKey(objectProperty.getName().getWireValue()) .docs(objectProperty.getDocs()) diff --git a/generators/java/generator-utils/src/main/java/com/fern/java/utils/TypeReferenceInlineChecker.java b/generators/java/generator-utils/src/main/java/com/fern/java/utils/TypeReferenceInlineChecker.java new file mode 100644 index 00000000000..668df1dbcd8 --- /dev/null +++ b/generators/java/generator-utils/src/main/java/com/fern/java/utils/TypeReferenceInlineChecker.java @@ -0,0 +1,81 @@ +package com.fern.java.utils; + +import com.fern.ir.model.types.ContainerType; +import com.fern.ir.model.types.Literal; +import com.fern.ir.model.types.MapType; +import com.fern.ir.model.types.NamedType; +import com.fern.ir.model.types.PrimitiveType; +import com.fern.ir.model.types.TypeDeclaration; +import com.fern.ir.model.types.TypeReference; +import com.fern.java.AbstractGeneratorContext; +import java.util.Optional; + +public class TypeReferenceInlineChecker implements TypeReference.Visitor, ContainerType.Visitor { + + private final AbstractGeneratorContext generatorContext; + + public TypeReferenceInlineChecker(AbstractGeneratorContext generatorContext) { + this.generatorContext = generatorContext; + } + + // Handle main types + + @Override + public Boolean visitContainer(ContainerType containerType) { + return containerType.visit(this); + } + + @Override + public Boolean visitNamed(NamedType namedType) { + // TODO(ajgateno): Tracking in FER-4050 that we can't just get inline from namedType.getInline() + Optional existingTypeDeclaration = + Optional.ofNullable(generatorContext.getTypeDeclarations().get(namedType.getTypeId())); + return existingTypeDeclaration + .map(declaration -> declaration.getInline().orElse(false)) + .orElse(false); + } + + @Override + public Boolean visitPrimitive(PrimitiveType primitiveType) { + return false; + } + + @Override + public Boolean visitUnknown() { + return false; + } + + // Handle container types + + @Override + public Boolean visitList(TypeReference typeReference) { + return typeReference.visit(this); + } + + @Override + public Boolean visitMap(MapType mapType) { + return mapType.getKeyType().visit(this) || mapType.getValueType().visit(this); + } + + @Override + public Boolean visitOptional(TypeReference typeReference) { + return typeReference.visit(this); + } + + @Override + public Boolean visitSet(TypeReference typeReference) { + return typeReference.visit(this); + } + + @Override + public Boolean visitLiteral(Literal literal) { + return false; + } + + // Unknown + + @Override + public Boolean _visitUnknown(Object o) { + return false; + } +} diff --git a/generators/java/model/versions.yml b/generators/java/model/versions.yml index 67b00dc1e3c..95f5bf9f0a8 100644 --- a/generators/java/model/versions.yml +++ b/generators/java/model/versions.yml @@ -1,3 +1,10 @@ +- changelogEntry: + - summary: | + Omit methods with inlined types from interface definitions. + type: fix + createdAt: '2025-01-16' + irVersion: 53 + version: 1.4.2 - changelogEntry: - summary: | Fix union inline type name conflict resolution. diff --git a/generators/java/sdk/versions.yml b/generators/java/sdk/versions.yml index e3240569517..c8fddeffca1 100644 --- a/generators/java/sdk/versions.yml +++ b/generators/java/sdk/versions.yml @@ -1,3 +1,10 @@ +- changelogEntry: + - summary: | + Omit methods with inlined types from interface definitions. + type: fix + createdAt: '2025-01-16' + irVersion: 53 + version: 2.10.2 - changelogEntry: - summary: | Fix union inline type name conflict resolution. diff --git a/generators/java/spring/versions.yml b/generators/java/spring/versions.yml index 56ab4b0a07c..f5b584af482 100644 --- a/generators/java/spring/versions.yml +++ b/generators/java/spring/versions.yml @@ -1,3 +1,10 @@ +- changelogEntry: + - summary: | + Omit methods with inlined types from interface definitions. + type: fix + createdAt: '2025-01-16' + irVersion: 53 + version: 1.4.2 - changelogEntry: - summary: | Fix union inline type name conflict resolution.