Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import io.github.blueprintplatform.openapi.generics.server.autoconfigure.properties.OpenApiGenericsProperties;
import io.github.blueprintplatform.openapi.generics.server.core.introspection.*;
import io.github.blueprintplatform.openapi.generics.server.core.introspection.container.DefaultSupportedContainerTypesResolver;
import io.github.blueprintplatform.openapi.generics.server.core.introspection.container.SupportedContainerTypesResolver;
import io.github.blueprintplatform.openapi.generics.server.core.introspection.container.resolver.ConfiguredContainerTypesResolver;
import io.github.blueprintplatform.openapi.generics.server.core.introspection.container.resolver.DefaultSupportedContainerTypesResolver;
import io.github.blueprintplatform.openapi.generics.server.core.introspection.container.resolver.SupportedContainerTypesResolver;
import io.github.blueprintplatform.openapi.generics.server.core.pipeline.OpenApiPipelineOrchestrator;
import io.github.blueprintplatform.openapi.generics.server.core.schema.ContractSchemaExclusionApplier;
import io.github.blueprintplatform.openapi.generics.server.core.schema.WrapperSchemaEnricher;
import io.github.blueprintplatform.openapi.generics.server.core.schema.WrapperSchemaProcessor;
import io.github.blueprintplatform.openapi.generics.server.core.validation.OpenApiContractGuard;
import io.github.blueprintplatform.openapi.generics.server.mvc.MvcResponseTypeDiscoveryStrategy;
Expand All @@ -20,7 +20,13 @@
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

@AutoConfiguration
/**
* Main auto-configuration for OpenAPI Generics server support.
*
* <p>Registers response type discovery, generic response introspection, contract guarding, and the
* OpenAPI customization pipeline.
*/
@AutoConfiguration(after = OpenApiGenericsSchemaAutoConfiguration.class)
@ConditionalOnClass(OpenApiCustomizer.class)
@ConditionalOnWebApplication
@EnableConfigurationProperties(OpenApiGenericsProperties.class)
Expand All @@ -40,11 +46,19 @@ public SupportedContainerTypesResolver supportedContainerTypesResolver() {
return new DefaultSupportedContainerTypesResolver();
}

@Bean
@ConditionalOnMissingBean
public ConfiguredContainerTypesResolver configuredContainerTypesResolver() {
return new ConfiguredContainerTypesResolver();
}

@Bean
@ConditionalOnMissingBean
public ResponseIntrospectionPolicyResolver responseIntrospectionPolicyResolver(
SupportedContainerTypesResolver supportedContainerTypesResolver) {
return new ResponseIntrospectionPolicyResolver(supportedContainerTypesResolver);
SupportedContainerTypesResolver supportedContainerTypesResolver,
ConfiguredContainerTypesResolver configuredContainerTypesResolver) {
return new ResponseIntrospectionPolicyResolver(
supportedContainerTypesResolver, configuredContainerTypesResolver);
}

@Bean
Expand All @@ -66,12 +80,6 @@ public ContractSchemaExclusionApplier schemaGenerationControlMarker() {
return new ContractSchemaExclusionApplier();
}

@Bean
@ConditionalOnMissingBean
public WrapperSchemaProcessor wrapperSchemaProcessor(WrapperSchemaEnricher enricher) {
return new WrapperSchemaProcessor(enricher);
}

@Bean
@ConditionalOnMissingBean
public OpenApiContractGuard openApiContractGuard() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,16 @@ public class OpenApiGenericsMissingDependencyAutoConfiguration {

This starter activates only when Springdoc is present.

To enable OpenAPI customization, add one of the following:

- org.springdoc:springdoc-openapi-starter-webmvc-ui
- org.springdoc:springdoc-openapi-starter-webflux-ui
To enable OpenAPI customization, add dependency on Springdoc OpenAPI in your build configuration:
- For Maven:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>

-------------------------------------------------------------------------
""";

/**
* Logs a warning message indicating that Springdoc is missing.
*
* <p>This method is invoked after bean initialization and provides a clear diagnostic message to
* the user.
*/
@PostConstruct
public void logWarning() {
log.warn(MESSAGE);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
package io.github.blueprintplatform.openapi.generics.server.autoconfigure;

import io.github.blueprintplatform.openapi.generics.server.core.schema.WrapperSchemaEnricher;
import io.github.blueprintplatform.openapi.generics.server.core.schema.extractor.ContentArrayItemExtractor;
import io.github.blueprintplatform.openapi.generics.server.core.schema.extractor.DirectArrayItemExtractor;
import io.github.blueprintplatform.openapi.generics.server.core.schema.resolver.ComponentContainerSchemaResolver;
import io.github.blueprintplatform.openapi.generics.server.core.schema.resolver.WrapperPayloadArraySchemaResolver;
import io.github.blueprintplatform.openapi.generics.server.core.schema.strategy.*;
import java.util.List;
import io.github.blueprintplatform.openapi.generics.server.core.schema.WrapperSchemaProcessor;
import io.github.blueprintplatform.openapi.generics.server.core.schema.enrichment.ContainerSchemaMetadataResolver;
import io.github.blueprintplatform.openapi.generics.server.core.schema.enrichment.WrapperSchemaEnricher;
import io.github.blueprintplatform.openapi.generics.server.core.schema.extraction.ArrayItemReferenceExtractor;
import io.github.blueprintplatform.openapi.generics.server.core.schema.resolution.ComponentContainerSchemaResolver;
import io.github.blueprintplatform.openapi.generics.server.core.schema.resolution.WrapperPayloadArraySchemaResolver;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;

/**
* Schema auto-configuration for OpenAPI Generics server support.
*
* <p>Registers schema resolution and enrichment components used to process projected generic
* wrapper schemas.
*/
@AutoConfiguration(before = OpenApiGenericsAutoConfiguration.class)
@ConditionalOnClass(OpenApiCustomizer.class)
@ConditionalOnWebApplication
public class OpenApiGenericsSchemaAutoConfiguration {

@Bean
@ConditionalOnMissingBean(ContentArrayItemExtractor.class)
public ContentArrayItemExtractor contentArrayItemExtractor() {
return new ContentArrayItemExtractor();
}

@Bean
@ConditionalOnMissingBean(DirectArrayItemExtractor.class)
public DirectArrayItemExtractor directArrayItemExtractor() {
return new DirectArrayItemExtractor();
@ConditionalOnMissingBean(ArrayItemReferenceExtractor.class)
public ArrayItemReferenceExtractor arrayItemReferenceExtractor() {
return new ArrayItemReferenceExtractor();
}

@Bean
Expand All @@ -44,41 +43,27 @@ public WrapperPayloadArraySchemaResolver wrapperPayloadArraySchemaResolver() {
}

@Bean
@ConditionalOnMissingBean(PageContainerSchemaStrategy.class)
public PageContainerSchemaStrategy pageContainerSchemaStrategy(
ComponentContainerSchemaResolver componentContainerSchemaResolver,
ContentArrayItemExtractor contentArrayItemExtractor) {
return new PageContainerSchemaStrategy(
componentContainerSchemaResolver, contentArrayItemExtractor);
}

@Bean
@ConditionalOnMissingBean(ListContainerSchemaStrategy.class)
public ListContainerSchemaStrategy listContainerSchemaStrategy(
WrapperPayloadArraySchemaResolver wrapperPayloadArraySchemaResolver,
DirectArrayItemExtractor directArrayItemExtractor) {
return new ListContainerSchemaStrategy(
wrapperPayloadArraySchemaResolver, directArrayItemExtractor);
}

@Bean
@ConditionalOnMissingBean(SetContainerSchemaStrategy.class)
public SetContainerSchemaStrategy setContainerSchemaStrategy(
@ConditionalOnMissingBean
public ContainerSchemaMetadataResolver containerSchemaMetadataResolver(
WrapperPayloadArraySchemaResolver wrapperPayloadArraySchemaResolver,
DirectArrayItemExtractor directArrayItemExtractor) {
return new SetContainerSchemaStrategy(
wrapperPayloadArraySchemaResolver, directArrayItemExtractor);
ComponentContainerSchemaResolver componentContainerSchemaResolver,
ArrayItemReferenceExtractor arrayItemReferenceExtractor) {
return new ContainerSchemaMetadataResolver(
wrapperPayloadArraySchemaResolver,
componentContainerSchemaResolver,
arrayItemReferenceExtractor);
}

@Bean
@ConditionalOnMissingBean
public ContainerSchemaRegistry containerSchemaRegistry(List<ContainerSchemaStrategy> strategies) {
return new ContainerSchemaRegistry(strategies);
public WrapperSchemaEnricher wrapperSchemaEnricher(
ContainerSchemaMetadataResolver containerSchemaMetadataResolver) {
return new WrapperSchemaEnricher(containerSchemaMetadataResolver);
}

@Bean
@ConditionalOnMissingBean
public WrapperSchemaEnricher wrapperSchemaEnricher(ContainerSchemaRegistry registry) {
return new WrapperSchemaEnricher(registry);
public WrapperSchemaProcessor wrapperSchemaProcessor(WrapperSchemaEnricher enricher) {
return new WrapperSchemaProcessor(enricher);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.github.blueprintplatform.openapi.generics.server.autoconfigure.properties;

/**
* Configuration describing a custom generic container contract.
*
* <p>Each configured container becomes eligible for deterministic generic reconstruction during
* OpenAPI projection.
*
* @param type fully-qualified generic container class name
* @param itemProperty JSON property containing the generic item collection
*/
public record ContainerProperties(String type, String itemProperty) {}
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package io.github.blueprintplatform.openapi.generics.server.autoconfigure.properties;

import jakarta.validation.Valid;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

/**
* Configuration properties for the OpenAPI Generics server starter.
*
* @param envelope envelope-related configuration
* @param containers custom generic container contract configuration
*/
@Validated
@ConfigurationProperties(prefix = "openapi-generics")
public record OpenApiGenericsProperties(@Valid EnvelopeProperties envelope) {}
public record OpenApiGenericsProperties(
@Valid EnvelopeProperties envelope, @Valid List<ContainerProperties> containers) {}
Original file line number Diff line number Diff line change
@@ -1,36 +1,16 @@
package io.github.blueprintplatform.openapi.generics.server.core.introspection;

import io.github.blueprintplatform.openapi.generics.server.core.introspection.container.SupportedContainerType;
import io.github.blueprintplatform.openapi.generics.server.core.introspection.container.descriptor.SupportedContainerDescriptor;
import java.util.Set;

/**
* Immutable configuration describing how response types should be interpreted by the introspection
* pipeline.
* Defines the active response introspection policy.
*
* <p>This policy defines:
*
* <ul>
* <li>Which envelope type should be recognized during response analysis
* <li>Which property inside the envelope represents the payload
* <li>Which container types are supported for generic reconstruction
* </ul>
*
* <p>For the default platform configuration this typically corresponds to:
*
* <pre>{@code
* ServiceResponse<T>
* ServiceResponse<Page<T>>
* ServiceResponse<List<T>>
* }</pre>
*
* <p>Additional containers may be contributed through the {@link SupportedContainerType} model
* without changing the core introspection algorithm.
*
* @param envelopeType envelope type to detect (for example {@code ServiceResponse})
* @param payloadPropertyName property representing the payload within the envelope
* @param supportedContainers supported generic container definitions
* @param envelopeType active response envelope type
* @param payloadPropertyName JSON property carrying the envelope payload
* @param supportedContainers supported generic container contracts
*/
public record ResponseIntrospectionPolicy(
Class<?> envelopeType,
String payloadPropertyName,
Set<SupportedContainerType> supportedContainers) {}
Set<SupportedContainerDescriptor> supportedContainers) {}
Loading
Loading