Skip to content

Commit a8169f0

Browse files
authored
Property binding for docket configuration (#123)
1 parent 6dbd839 commit a8169f0

File tree

46 files changed

+1172
-52
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1172
-52
lines changed

springwolf-core/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ dependencies {
3434

3535
compileOnly 'org.projectlombok:lombok:1.18.22'
3636
annotationProcessor 'org.projectlombok:lombok:1.18.22'
37+
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
3738

3839

3940
testImplementation 'org.projectlombok:lombok:1.18.22'
@@ -115,4 +116,3 @@ signing {
115116
useInMemoryPgpKeys (signingKey, signingPassword)
116117
sign publishing.publications.mavenJava
117118
}
118-
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.github.stavshamir.springwolf;
2+
3+
public class SpringWolfConfigConstants {
4+
5+
public static final String SPRINGWOLF_CONFIG_PREFIX = "springwolf";
6+
7+
public static final String SPRINGWOLF_ENABLED = SPRINGWOLF_CONFIG_PREFIX + ".enabled";
8+
public static final String SPRINGWOLF_PLUGIN_CONFIG_PREFIX = SPRINGWOLF_CONFIG_PREFIX + ".plugin";
9+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package io.github.stavshamir.springwolf;
2+
3+
import com.asyncapi.v2.model.info.Contact;
4+
import com.asyncapi.v2.model.info.License;
5+
import com.asyncapi.v2.model.server.Server;
6+
import io.github.stavshamir.springwolf.configuration.AsyncApiDocket;
7+
import lombok.Getter;
8+
import lombok.Setter;
9+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
10+
import org.springframework.boot.context.properties.ConfigurationProperties;
11+
import org.springframework.boot.context.properties.NestedConfigurationProperty;
12+
import org.springframework.context.annotation.Configuration;
13+
14+
import javax.annotation.Nullable;
15+
import java.util.Map;
16+
17+
@Configuration
18+
@ConfigurationProperties(prefix = SpringWolfConfigConstants.SPRINGWOLF_CONFIG_PREFIX)
19+
@ConditionalOnProperty(name = SpringWolfConfigConstants.SPRINGWOLF_ENABLED, matchIfMissing = true)
20+
@Getter
21+
@Setter
22+
public class SpringWolfConfigProperties {
23+
24+
private boolean enabled = true;
25+
26+
@Nullable
27+
private ConfigDocket docket;
28+
29+
@Getter
30+
@Setter
31+
public static class ConfigDocket {
32+
33+
/**
34+
* The base package to scan for listeners which are declared inside a class annotated with @Component or @Service.
35+
*
36+
* @see AsyncApiDocket.AsyncApiDocketBuilder#basePackage(String)
37+
*/
38+
@Nullable
39+
private String basePackage;
40+
41+
@Nullable
42+
private Map<String, Server> servers;
43+
44+
/**
45+
* The object provides metadata about the API. The metadata can be used by the clients if needed.
46+
*
47+
* @see com.asyncapi.v2.model.info.Info
48+
*/
49+
@Nullable
50+
private Info info;
51+
52+
@Getter
53+
@Setter
54+
public static class Info {
55+
56+
/**
57+
* The title of the application
58+
*
59+
* @see com.asyncapi.v2.model.info.Info#getTitle()
60+
*/
61+
@Nullable
62+
private String title;
63+
64+
/**
65+
* Required. Provides the version of the application API (not to be confused with the specification version).
66+
*
67+
* @see com.asyncapi.v2.model.info.Info#getVersion()
68+
*/
69+
@Nullable
70+
private String version;
71+
72+
/**
73+
* A short description of the application. CommonMark syntax can be used for rich text representation.
74+
*
75+
* @see com.asyncapi.v2.model.info.Info#getDescription()
76+
*/
77+
@Nullable
78+
private String description;
79+
80+
/**
81+
* A URL to the Terms of Service for the API. MUST be in the format of a URL.
82+
* {@link com.asyncapi.v2.model.info.Info#getTermsOfService()}
83+
*/
84+
@Nullable
85+
private String termsOfService;
86+
87+
@NestedConfigurationProperty
88+
@Nullable
89+
private Contact contact;
90+
91+
@NestedConfigurationProperty
92+
@Nullable
93+
private License license;
94+
}
95+
96+
}
97+
98+
99+
}

springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/DefaultAsyncApiService.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.github.stavshamir.springwolf.asyncapi.types.AsyncAPI;
44
import io.github.stavshamir.springwolf.asyncapi.types.Components;
55
import io.github.stavshamir.springwolf.configuration.AsyncApiDocket;
6+
import io.github.stavshamir.springwolf.configuration.AsyncApiDocketService;
67
import io.github.stavshamir.springwolf.schemas.SchemasService;
78
import lombok.RequiredArgsConstructor;
89
import lombok.extern.slf4j.Slf4j;
@@ -15,7 +16,7 @@
1516
@RequiredArgsConstructor
1617
public class DefaultAsyncApiService implements AsyncApiService {
1718

18-
private final AsyncApiDocket docket;
19+
private final AsyncApiDocketService asyncApiDocketService;
1920
private final ChannelsService channelsService;
2021
private final SchemasService schemasService;
2122

@@ -25,6 +26,8 @@ public class DefaultAsyncApiService implements AsyncApiService {
2526
void buildAsyncApi() {
2627
log.debug("Building AsyncAPI document");
2728

29+
AsyncApiDocket docket = asyncApiDocketService.getAsyncApiDocket();
30+
2831
Components components = Components.builder()
2932
.schemas(schemasService.getDefinitions())
3033
.build();

springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/ConsumerOperationDataScanner.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata;
22

33
import io.github.stavshamir.springwolf.asyncapi.types.OperationData;
4-
import io.github.stavshamir.springwolf.configuration.AsyncApiDocket;
4+
import io.github.stavshamir.springwolf.configuration.AsyncApiDocketService;
55
import io.github.stavshamir.springwolf.schemas.SchemasService;
66
import lombok.RequiredArgsConstructor;
77
import lombok.extern.slf4j.Slf4j;
@@ -15,7 +15,7 @@
1515
@Component
1616
public class ConsumerOperationDataScanner extends AbstractOperationDataScanner {
1717

18-
private final AsyncApiDocket docket;
18+
private final AsyncApiDocketService asyncApiDocketService;
1919
private final SchemasService schemasService;
2020

2121
@Override
@@ -25,7 +25,7 @@ protected SchemasService getSchemaService() {
2525

2626
@Override
2727
protected List<OperationData> getOperationData() {
28-
return new ArrayList<>(docket.getConsumers());
28+
return new ArrayList<>(asyncApiDocketService.getAsyncApiDocket().getConsumers());
2929
}
3030

3131
@Override

springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/ProducerOperationDataScanner.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata;
22

33
import io.github.stavshamir.springwolf.asyncapi.types.OperationData;
4-
import io.github.stavshamir.springwolf.configuration.AsyncApiDocket;
4+
import io.github.stavshamir.springwolf.configuration.AsyncApiDocketService;
55
import io.github.stavshamir.springwolf.schemas.SchemasService;
66
import lombok.RequiredArgsConstructor;
77
import lombok.extern.slf4j.Slf4j;
@@ -15,7 +15,7 @@
1515
@Component
1616
public class ProducerOperationDataScanner extends AbstractOperationDataScanner {
1717

18-
private final AsyncApiDocket docket;
18+
private final AsyncApiDocketService asyncApiDocketService;
1919
private final SchemasService schemasService;
2020

2121
@Override
@@ -25,7 +25,7 @@ protected SchemasService getSchemaService() {
2525

2626
@Override
2727
protected List<OperationData> getOperationData() {
28-
return new ArrayList<>(docket.getProducers());
28+
return new ArrayList<>(asyncApiDocketService.getAsyncApiDocket().getProducers());
2929
}
3030

3131
@Override

springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/classes/AbstractAnnotatedClassScanner.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package io.github.stavshamir.springwolf.asyncapi.scanners.classes;
22

3-
import io.github.stavshamir.springwolf.configuration.AsyncApiDocket;
3+
import io.github.stavshamir.springwolf.configuration.AsyncApiDocketService;
44
import lombok.extern.slf4j.Slf4j;
55
import org.apache.commons.lang3.StringUtils;
66
import org.springframework.beans.factory.annotation.Autowired;
@@ -18,7 +18,7 @@
1818
public abstract class AbstractAnnotatedClassScanner<T extends Annotation> implements ClassScanner {
1919

2020
@Autowired
21-
private AsyncApiDocket docket;
21+
private AsyncApiDocketService asyncApiDocketService;
2222

2323
/**
2424
* @return The class object of the annotation to scan.
@@ -27,7 +27,7 @@ public abstract class AbstractAnnotatedClassScanner<T extends Annotation> implem
2727

2828
@Override
2929
public Set<Class<?>> scan() {
30-
String basePackage = docket.getBasePackage();
30+
String basePackage = asyncApiDocketService.getAsyncApiDocket().getBasePackage();
3131
if (StringUtils.isBlank(basePackage)) {
3232
throw new IllegalArgumentException("Base package must not be blank");
3333
}

springwolf-core/src/main/java/io/github/stavshamir/springwolf/configuration/AsyncApiDocket.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212
import java.util.List;
1313
import java.util.Map;
1414

15+
/**
16+
* Use to (manually) configure springwolf
17+
* <p>
18+
* This will not be the final AsyncApiDocket, use {@link AsyncApiDocketService#getAsyncApiDocket()} to get it.
19+
* This will not be the final api definition, use {@link io.github.stavshamir.springwolf.asyncapi.AsyncApiService} to get it.
20+
*/
1521
@Data
1622
@Builder
1723
public class AsyncApiDocket {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package io.github.stavshamir.springwolf.configuration;
2+
3+
public interface AsyncApiDocketService {
4+
AsyncApiDocket getAsyncApiDocket();
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package io.github.stavshamir.springwolf.configuration;
2+
3+
import com.asyncapi.v2.model.info.Info;
4+
import io.github.stavshamir.springwolf.SpringWolfConfigConstants;
5+
import io.github.stavshamir.springwolf.SpringWolfConfigProperties;
6+
import lombok.RequiredArgsConstructor;
7+
import lombok.extern.slf4j.Slf4j;
8+
import org.springframework.stereotype.Service;
9+
10+
import javax.annotation.Nullable;
11+
import java.util.Optional;
12+
13+
@Slf4j
14+
@Service
15+
@RequiredArgsConstructor
16+
public class DefaultAsyncApiDocketService implements AsyncApiDocketService {
17+
18+
/**
19+
* Docket defined by the user as a @Bean
20+
*/
21+
private final Optional<AsyncApiDocket> customDocket;
22+
23+
/**
24+
* Docket definition in application.properties
25+
*/
26+
private final Optional<SpringWolfConfigProperties> configProperties;
27+
28+
@Override
29+
public AsyncApiDocket getAsyncApiDocket() {
30+
if (customDocket.isPresent()) {
31+
log.debug("Reading springwolf configuration from custom defined @Bean AsyncApiDocket");
32+
return customDocket.get();
33+
} else if (configProperties.isPresent()) {
34+
log.debug("Reading springwolf configuration from application.properties files");
35+
return parseApplicationConfigProperties(configProperties.get());
36+
}
37+
throw new IllegalArgumentException("No springwolf configuration found. " +
38+
"Either define the properties in the application.properties under the " + SpringWolfConfigConstants.SPRINGWOLF_CONFIG_PREFIX + " prefix " +
39+
"or add a @Bean AsyncApiDocket to the spring context");
40+
}
41+
42+
private AsyncApiDocket parseApplicationConfigProperties(SpringWolfConfigProperties configProperties) {
43+
if (configProperties.getDocket() == null ||
44+
configProperties.getDocket().getBasePackage() == null) {
45+
throw new IllegalArgumentException("One or more required fields (docket, basePackage) " +
46+
"in application.properties with path prefix " + SpringWolfConfigConstants.SPRINGWOLF_CONFIG_PREFIX + " is not set.");
47+
}
48+
49+
Info info = buildInfo(configProperties.getDocket().getInfo());
50+
51+
return AsyncApiDocket.builder()
52+
.basePackage(configProperties.getDocket().getBasePackage())
53+
.info(info)
54+
.servers(configProperties.getDocket().getServers())
55+
.build();
56+
}
57+
58+
private static Info buildInfo(@Nullable SpringWolfConfigProperties.ConfigDocket.Info info) {
59+
if (info == null ||
60+
info.getVersion() == null ||
61+
info.getTitle() == null) {
62+
throw new IllegalArgumentException("One or more required fields of the info object (title, version) " +
63+
"in application.properties with path prefix " + SpringWolfConfigConstants.SPRINGWOLF_CONFIG_PREFIX + " is not set.");
64+
}
65+
66+
return Info.builder()
67+
.version(info.getVersion())
68+
.title(info.getTitle())
69+
.description(info.getDescription())
70+
.contact(info.getContact())
71+
.license(info.getLicense())
72+
.build();
73+
}
74+
75+
76+
}

0 commit comments

Comments
 (0)