Skip to content

Commit

Permalink
feat(core): add configuration option to use fully qualified names in …
Browse files Browse the repository at this point in the history
…schemas (#393)

* feat(core): add configuration option to use fully qualified names in schemas

default is false (unchanged behavior)

Co-authored-by: Timon Back <[email protected]>

* feat(core): rebase to master

* test(core): update DefaultSchemaServiceTest

* feat(example): Use fqn in example

* feat(ui): show only schema type (not fqn) in ui

* feat(core): Use class name for title, not fqn

* feat(ui): ui can show fqn payload

* test(plugin): add SpringwolfConfigProperties in test context

* feat(core): use swagger-core getUseFqn to reset fqn

* test(amqp): update asyncapi_withdocketfromenvironment.json after rebase

---------

Co-authored-by: Timon Back <[email protected]>
Co-authored-by: Timon Back <[email protected]>
  • Loading branch information
3 people authored Oct 27, 2023
1 parent 89c7b00 commit adc1d80
Show file tree
Hide file tree
Showing 36 changed files with 347 additions and 229 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,11 @@ public ChannelsService channelsService(List<? extends ChannelsScanner> channelsS

@Bean
@ConditionalOnMissingBean
public SchemasService schemasService(List<ModelConverter> modelConverters, ExampleGenerator exampleGenerator) {
return new DefaultSchemasService(modelConverters, exampleGenerator);
public SchemasService schemasService(
List<ModelConverter> modelConverters,
ExampleGenerator exampleGenerator,
SpringwolfConfigProperties springwolfConfigProperties) {
return new DefaultSchemasService(modelConverters, exampleGenerator, springwolfConfigProperties);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ private Message buildMessage(Method method) {

return Message.builder()
.name(payloadType.getName())
.title(modelName)
.title(payloadType.getSimpleName())
.payload(PayloadReference.fromModelName(modelName))
.headers(HeaderReference.fromModelName(headerModelName))
.bindings(buildMessageBinding(method))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ private ChannelItem buildChannel(

Message message = Message.builder()
.name(payloadType.getName())
.title(modelName)
.title(payloadType.getSimpleName())
.payload(PayloadReference.fromModelName(modelName))
.headers(HeaderReference.fromModelName(headerModelName))
.bindings(messageBinding)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ private Message buildMessage(OperationData operationData) {

var builder = Message.builder()
.name(payloadType.getName())
.title(modelName)
.title(payloadType.getSimpleName())
.description(description)
.payload(PayloadReference.fromModelName(modelName))
.headers(HeaderReference.fromModelName(headerModelName))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ public enum InitMode {
*/
private InitMode initMode = InitMode.FAIL_FAST;

/**
* Use fully qualified names for the schema classes
*
* Example:
* useFqn = true -> java.lang.String
* useFqn = false -> String
*/
private boolean useFqn = false;

@Nullable
private Endpoint endpoint;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
package io.github.stavshamir.springwolf.schemas;

import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.AsyncHeaders;
import io.github.stavshamir.springwolf.configuration.properties.SpringwolfConfigProperties;
import io.github.stavshamir.springwolf.schemas.example.ExampleGenerator;
import io.swagger.v3.core.converter.ModelConverter;
import io.swagger.v3.core.converter.ModelConverters;
import io.swagger.v3.core.jackson.TypeNameResolver;
import io.swagger.v3.oas.models.media.MapSchema;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.StringSchema;
Expand All @@ -15,20 +17,26 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

@Slf4j
public class DefaultSchemasService implements SchemasService {

private final ModelConverters converter = ModelConverters.getInstance();
private final ExampleGenerator exampleGenerator;
private final SpringwolfConfigProperties properties;

private final Map<String, Schema> definitions = new HashMap<>();
private Map<String, Schema> finalizedDefinitions = null;

public DefaultSchemasService(List<ModelConverter> externalModelConverters, ExampleGenerator exampleGenerator) {
public DefaultSchemasService(
List<ModelConverter> externalModelConverters,
ExampleGenerator exampleGenerator,
SpringwolfConfigProperties properties) {

externalModelConverters.forEach(converter::addConverter);
this.exampleGenerator = exampleGenerator;
this.properties = properties;
}

@Override
Expand Down Expand Up @@ -61,10 +69,10 @@ public String register(AsyncHeaders headers) {
public String register(Class<?> type) {
log.debug("Registering schema for {}", type.getSimpleName());

Map<String, Schema> schemas = converter.readAll(type);
Map<String, Schema> schemas = runWithFqnSetting((unused) -> converter.readAll(type));
this.definitions.putAll(schemas);

if (schemas.size() == 0 && type.equals(String.class)) {
if (schemas.isEmpty() && type.equals(String.class)) {
this.definitions.put("String", new StringSchema());
return "String";
}
Expand All @@ -81,6 +89,20 @@ public String register(Class<?> type) {
return type.getSimpleName();
}

private <R> R runWithFqnSetting(Function<Void, R> callable) {
boolean previousUseFqn = TypeNameResolver.std.getUseFqn();
if (properties.isUseFqn()) {
TypeNameResolver.std.setUseFqn(true);
}

R result = callable.apply(null);

if (properties.isUseFqn()) {
TypeNameResolver.std.setUseFqn(previousUseFqn);
}
return result;
}

private void removeSwaggerSchemaFields(String schemaName, Schema schema) {
schema.setAdditionalProperties(null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.AsyncHeaders;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.HeaderReference;
import io.github.stavshamir.springwolf.configuration.AsyncApiDocket;
import io.github.stavshamir.springwolf.configuration.properties.SpringwolfConfigProperties;
import io.github.stavshamir.springwolf.schemas.DefaultSchemasService;
import io.github.stavshamir.springwolf.schemas.example.ExampleJsonGenerator;
import lombok.Data;
Expand All @@ -33,7 +34,12 @@

@ExtendWith(SpringExtension.class)
@ContextConfiguration(
classes = {TestMethodLevelListenerScanner.class, DefaultSchemasService.class, ExampleJsonGenerator.class})
classes = {
TestMethodLevelListenerScanner.class,
DefaultSchemasService.class,
ExampleJsonGenerator.class,
SpringwolfConfigProperties.class
})
class TestMethodLevelListenerScannerIntegrationTest {

@Autowired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.HeaderReference;
import io.github.stavshamir.springwolf.configuration.AsyncApiDocket;
import io.github.stavshamir.springwolf.configuration.AsyncApiDocketService;
import io.github.stavshamir.springwolf.configuration.properties.SpringwolfConfigProperties;
import io.github.stavshamir.springwolf.schemas.DefaultSchemasService;
import io.github.stavshamir.springwolf.schemas.example.ExampleJsonGenerator;
import io.swagger.v3.oas.annotations.media.Schema;
Expand All @@ -35,7 +36,12 @@

@ExtendWith(SpringExtension.class)
@ContextConfiguration(
classes = {ConsumerOperationDataScanner.class, DefaultSchemasService.class, ExampleJsonGenerator.class})
classes = {
ConsumerOperationDataScanner.class,
DefaultSchemasService.class,
ExampleJsonGenerator.class,
SpringwolfConfigProperties.class,
})
class ConsumerOperationDataScannerIntegrationTest {

@Autowired
Expand Down Expand Up @@ -73,8 +79,8 @@ void allFieldsConsumerData() {
.bindings(Map.of("kafka", new KafkaOperationBinding()))
.message(Message.builder()
.name(ExamplePayloadDto.class.getName())
.description(messageDescription)
.title(ExamplePayloadDto.class.getSimpleName())
.description(messageDescription)
.payload(PayloadReference.fromModelName(ExamplePayloadDto.class.getSimpleName()))
.headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName()))
.bindings(Map.of("kafka", new KafkaMessageBinding()))
Expand Down Expand Up @@ -144,16 +150,16 @@ void multipleConsumersForSameTopic() {
Set<Message> messages = Set.of(
Message.builder()
.name(ExamplePayloadDto.class.getName())
.description(messageDescription1)
.title(ExamplePayloadDto.class.getSimpleName())
.description(messageDescription1)
.payload(PayloadReference.fromModelName(ExamplePayloadDto.class.getSimpleName()))
.headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName()))
.bindings(Map.of("kafka", new KafkaMessageBinding()))
.build(),
Message.builder()
.name(AnotherExamplePayloadDto.class.getName())
.description(messageDescription2)
.title(AnotherExamplePayloadDto.class.getSimpleName())
.description(messageDescription2)
.payload(PayloadReference.fromModelName(AnotherExamplePayloadDto.class.getSimpleName()))
.headers(HeaderReference.fromModelName(AsyncHeaders.NOT_USED.getSchemaName()))
.bindings(Map.of("kafka", new KafkaMessageBinding()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.HeaderReference;
import io.github.stavshamir.springwolf.configuration.AsyncApiDocket;
import io.github.stavshamir.springwolf.configuration.AsyncApiDocketService;
import io.github.stavshamir.springwolf.configuration.properties.SpringwolfConfigProperties;
import io.github.stavshamir.springwolf.schemas.DefaultSchemasService;
import io.github.stavshamir.springwolf.schemas.example.ExampleJsonGenerator;
import io.swagger.v3.oas.annotations.media.Schema;
Expand All @@ -35,7 +36,12 @@

@ExtendWith(SpringExtension.class)
@ContextConfiguration(
classes = {ProducerOperationDataScanner.class, DefaultSchemasService.class, ExampleJsonGenerator.class})
classes = {
ProducerOperationDataScanner.class,
DefaultSchemasService.class,
ExampleJsonGenerator.class,
SpringwolfConfigProperties.class,
})
class ProducerOperationDataScannerIntegrationTest {

@Autowired
Expand Down Expand Up @@ -73,8 +79,8 @@ void allFieldsProducerData() {
.bindings(Map.of("kafka", new KafkaOperationBinding()))
.message(Message.builder()
.name(ExamplePayloadDto.class.getName())
.description(messageDescription1)
.title(ExamplePayloadDto.class.getSimpleName())
.description(messageDescription1)
.payload(PayloadReference.fromModelName(ExamplePayloadDto.class.getSimpleName()))
.headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName()))
.bindings(Map.of("kafka", new KafkaMessageBinding()))
Expand Down Expand Up @@ -144,16 +150,16 @@ void multipleProducersForSameTopic() {
Set<Message> messages = Set.of(
Message.builder()
.name(ExamplePayloadDto.class.getName())
.description(messageDescription1)
.title(ExamplePayloadDto.class.getSimpleName())
.description(messageDescription1)
.payload(PayloadReference.fromModelName(ExamplePayloadDto.class.getSimpleName()))
.headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName()))
.bindings(Map.of("kafka", new KafkaMessageBinding()))
.build(),
Message.builder()
.name(AnotherExamplePayloadDto.class.getName())
.description(messageDescription2)
.title(AnotherExamplePayloadDto.class.getSimpleName())
.description(messageDescription2)
.payload(PayloadReference.fromModelName(AnotherExamplePayloadDto.class.getSimpleName()))
.headers(HeaderReference.fromModelName(AsyncHeaders.NOT_USED.getSchemaName()))
.bindings(Map.of("kafka", new KafkaMessageBinding()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.PayloadReference;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.AsyncHeaders;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.HeaderReference;
import io.github.stavshamir.springwolf.configuration.properties.SpringwolfConfigProperties;
import io.github.stavshamir.springwolf.schemas.DefaultSchemasService;
import io.github.stavshamir.springwolf.schemas.example.ExampleJsonGenerator;
import io.swagger.v3.oas.annotations.media.Schema;
Expand Down Expand Up @@ -36,6 +37,7 @@
AsyncListenerAnnotationScanner.class,
DefaultSchemasService.class,
ExampleJsonGenerator.class,
SpringwolfConfigProperties.class,
TestOperationBindingProcessor.class
})
@TestPropertySource(properties = {"test.property.test-channel=test-channel", "test.property.description=description"})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.PayloadReference;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.AsyncHeaders;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.HeaderReference;
import io.github.stavshamir.springwolf.configuration.properties.SpringwolfConfigProperties;
import io.github.stavshamir.springwolf.schemas.DefaultSchemasService;
import io.github.stavshamir.springwolf.schemas.example.ExampleJsonGenerator;
import lombok.Data;
Expand All @@ -35,6 +36,7 @@
AsyncPublisherAnnotationScanner.class,
DefaultSchemasService.class,
ExampleJsonGenerator.class,
SpringwolfConfigProperties.class,
TestOperationBindingProcessor.class
})
@TestPropertySource(properties = {"test.property.test-channel=test-channel", "test.property.description=description"})
Expand Down Expand Up @@ -72,8 +74,7 @@ void scan_componentHasPublisherMethod() {
Message message = Message.builder()
.name(SimpleFoo.class.getName())
.title(SimpleFoo.class.getSimpleName())
// Message description is not supported yet
// .description("")
.description(null)
.payload(PayloadReference.fromModelName(SimpleFoo.class.getSimpleName()))
.headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName()))
.bindings(EMPTY_MAP)
Expand Down Expand Up @@ -104,8 +105,7 @@ void scan_componentHasPublisherMethodWithAllAttributes() {
Message message = Message.builder()
.name(SimpleFoo.class.getName())
.title(SimpleFoo.class.getSimpleName())
// Message description is not supported yet
// .description("description")
.description(null)
.payload(PayloadReference.fromModelName(SimpleFoo.class.getSimpleName()))
.headers(HeaderReference.fromModelName("TestSchema"))
.bindings(EMPTY_MAP)
Expand Down Expand Up @@ -136,8 +136,7 @@ void scan_componentHasMultiplePublisherAnnotations() {
Message message = Message.builder()
.name(SimpleFoo.class.getName())
.title(SimpleFoo.class.getSimpleName())
// Message description is not supported yet
// .description("")
.description(null)
.payload(PayloadReference.fromModelName(SimpleFoo.class.getSimpleName()))
.headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName()))
.bindings(EMPTY_MAP)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import io.github.stavshamir.springwolf.configuration.properties.SpringwolfConfigProperties;
import io.github.stavshamir.springwolf.schemas.example.ExampleGenerator;
import io.github.stavshamir.springwolf.schemas.example.ExampleJsonGenerator;
import io.swagger.v3.core.util.Json;
Expand All @@ -32,7 +33,8 @@
class DefaultSchemasServiceTest {

private final ExampleGenerator exampleGenerator = new ExampleJsonGenerator();
private final SchemasService schemasService = new DefaultSchemasService(List.of(), exampleGenerator);
private final SchemasService schemasService =
new DefaultSchemasService(List.of(), exampleGenerator, new SpringwolfConfigProperties());

private static final ObjectMapper objectMapper =
Json.mapper().enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS);
Expand Down Expand Up @@ -91,6 +93,28 @@ void classWithSchemaAnnotation() {
assertThat(modelName).isEqualTo("DifferentName");
}

@Test
void getDefinitionWithFqnClassName() throws IOException {
// given
SpringwolfConfigProperties properties = new SpringwolfConfigProperties();
properties.setUseFqn(true);

SchemasService schemasServiceWithFqn = new DefaultSchemasService(List.of(), exampleGenerator, properties);

// when
Class<?> clazz =
OneFieldFooWithFqn.class; // swagger seems to cache results. Therefore, a new class must be used.
schemasServiceWithFqn.register(clazz);
String actualDefinitions =
objectMapper.writer(printer).writeValueAsString(schemasServiceWithFqn.getDefinitions());

// then
System.out.println("Got: " + actualDefinitions);
String fqnClassName = clazz.getName();
assertThat(actualDefinitions).contains(fqnClassName);
assertThat(fqnClassName.length()).isGreaterThan(clazz.getSimpleName().length());
}

private String jsonResource(String path) throws IOException {
InputStream s = this.getClass().getResourceAsStream(path);
return new String(s.readAllBytes(), StandardCharsets.UTF_8);
Expand All @@ -103,6 +127,12 @@ private static class SimpleFoo {
private boolean b;
}

@Data
@NoArgsConstructor
private static class OneFieldFooWithFqn {
private String s;
}

@Data
@NoArgsConstructor
@Schema(description = "foo model")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ springwolf.docket.info.license.name=Apache License 2.0
springwolf.docket.info.license.extension-fields.x-desc=some description
springwolf.docket.servers.amqp.protocol=amqp
springwolf.docket.servers.amqp.url=${spring.rabbitmq.host}:${spring.rabbitmq.port}
springwolf.use-fqn=true

springwolf.plugin.amqp.publishing.enabled=true

Expand Down
Loading

0 comments on commit adc1d80

Please sign in to comment.