Skip to content

Commit 759e33d

Browse files
committed
put server url at interface if requested (#176)
1 parent fdf9085 commit 759e33d

File tree

11 files changed

+122
-11
lines changed

11 files changed

+122
-11
lines changed

openapi-processor-core/src/main/kotlin/io/openapiprocessor/core/converter/ApiOptions.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ class ApiOptions: MappingSettings {
9191
*/
9292
var jsonPropertyAnnotation = JsonPropertyAnnotationMode.Always
9393

94+
/**
95+
* enable/disable use of server url (optional).
96+
*/
97+
var serverPrefix = false
98+
99+
/**
100+
* index of the server to use as server prefix.
101+
*/
102+
var serverPrefixIndex: Int = 0
103+
94104
/**
95105
* provide additional type mapping information to map OpenAPI types to java types.
96106
*/
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/*
2+
* Copyright 2024 https://github.com/openapi-processor/openapi-processor-base
3+
* PDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.openapiprocessor.core.framework
7+
8+
enum class AnnotationType {
9+
INTERFACE_PATH_PREFIX
10+
}

openapi-processor-core/src/main/kotlin/io/openapiprocessor/core/framework/FrameworkAnnotations.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,12 @@ interface FrameworkAnnotations {
3030
*/
3131
fun getAnnotation(parameter: Parameter): Annotation
3232

33+
/**
34+
* provides the details of the requested annotation.
35+
*
36+
* @param type annotation type
37+
* @return annotation details
38+
*/
39+
40+
fun getAnnotation(type: AnnotationType): Annotation
3341
}

openapi-processor-core/src/main/kotlin/io/openapiprocessor/core/model/Annotation.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package io.openapiprocessor.core.model
77

88
import io.openapiprocessor.core.converter.mapping.ParameterValue
9+
import io.openapiprocessor.core.converter.mapping.SimpleParameterValue
910

1011
open class Annotation(
1112
private val canonicalName: String,
@@ -35,4 +36,18 @@ open class Annotation(
3536
*/
3637
val annotationName: String
3738
get() = "@${typeName}"
39+
40+
fun withParameter(parameter: String): Annotation {
41+
val newParameters = linkedMapOf<String, ParameterValue>()
42+
newParameters.putAll(parameters)
43+
newParameters[""] = SimpleParameterValue(parameter)
44+
return Annotation(canonicalName, newParameters)
45+
}
46+
47+
fun withParameter(key: String, parameter: ParameterValue): Annotation {
48+
val m = linkedMapOf<String, ParameterValue>()
49+
m.putAll(parameters)
50+
m[key] = parameter
51+
return Annotation(canonicalName, m)
52+
}
3853
}

openapi-processor-core/src/main/kotlin/io/openapiprocessor/core/model/Interface.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import io.openapiprocessor.core.writer.Identifier
1414
class Interface(
1515
val name: String,
1616
private val pkg: String,
17-
private val identifier: Identifier
17+
private val identifier: Identifier,
18+
val path: String? = null
1819
) {
1920
val endpoints: List<Endpoint> = mutableListOf()
2021

@@ -38,6 +39,10 @@ class Interface(
3839
endpoints.addAll(endpoint)
3940
}
4041

42+
fun hasPath(): Boolean {
43+
return path != null
44+
}
45+
4146
override fun toString(): String {
4247
return "$pkg.$name"
4348
}

openapi-processor-core/src/main/kotlin/io/openapiprocessor/core/writer/java/InterfaceWriter.kt

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ package io.openapiprocessor.core.writer.java
88
import io.openapiprocessor.core.converter.ApiOptions
99
import io.openapiprocessor.core.converter.MappingFinder
1010
import io.openapiprocessor.core.converter.MappingQuery
11+
import io.openapiprocessor.core.framework.AnnotationType
1112
import io.openapiprocessor.core.framework.FrameworkAnnotations
13+
import io.openapiprocessor.core.model.Annotation
1214
import io.openapiprocessor.core.model.Endpoint
1315
import io.openapiprocessor.core.model.EndpointResponse
1416
import io.openapiprocessor.core.model.Interface
@@ -25,18 +27,25 @@ class InterfaceWriter(
2527
private val methodWriter: MethodWriter,
2628
private val annotations: FrameworkAnnotations,
2729
private val validationAnnotations: BeanValidationFactory = BeanValidationFactory(apiOptions),
28-
private val importFilter: ImportFilter = DefaultImportFilter()
30+
private val importFilter: ImportFilter = DefaultImportFilter(),
2931
) {
32+
private val annotationWriter: AnnotationWriter = AnnotationWriter()
33+
3034
fun write(target: Writer, itf: Interface) {
3135
target.write ("package ${itf.getPackageName()};\n\n")
3236

33-
val imports: List<String> = collectImports (itf.getPackageName(), itf.endpoints)
37+
val imports: List<String> = collectImports (itf, itf.getPackageName(), itf.endpoints)
3438
imports.forEach {
3539
target.write("import ${it};\n")
3640
}
3741
target.write("\n")
3842

3943
generatedWriter.writeUse(target)
44+
45+
if (apiOptions.serverPrefix && itf.hasPath()) {
46+
annotationWriter.write(target, getPrefixAnnotation(itf.path))
47+
target.write("\n")
48+
}
4049
target.write("public interface ${itf.getInterfaceName()} {\n\n")
4150

4251
itf.endpoints.forEach { ep ->
@@ -49,7 +58,7 @@ class InterfaceWriter(
4958
target.write ("}\n")
5059
}
5160

52-
private fun collectImports(packageName: String, endpoints: List<Endpoint>): List<String> {
61+
private fun collectImports(itf: Interface, packageName: String, endpoints: List<Endpoint>): List<String> {
5362
val imports: MutableSet<String> = mutableSetOf()
5463

5564
imports.addAll(generatedWriter.getImports())
@@ -59,6 +68,10 @@ class InterfaceWriter(
5968
imports.addAll(annotation.imports)
6069
imports.addAll(annotation.referencedImports)
6170

71+
if (apiOptions.serverPrefix && itf.hasPath()) {
72+
imports.addAll(getPrefixAnnotation().imports)
73+
}
74+
6275
if (ep.deprecated) {
6376
imports.add (java.lang.Deprecated::class.java.canonicalName)
6477
}
@@ -135,4 +148,13 @@ class InterfaceWriter(
135148
imports.addAll(responseImports)
136149
}
137150
}
151+
152+
private fun getPrefixAnnotation(path: String? = null): Annotation {
153+
val annotation = annotations.getAnnotation(AnnotationType.INTERFACE_PATH_PREFIX)
154+
return if (path == null) {
155+
annotation
156+
} else {
157+
annotation.withParameter(""""$path"""")
158+
}
159+
}
138160
}

openapi-processor-core/src/test/groovy/io/openapiprocessor/core/writer/java/InterfaceWriterGSpec.groovy

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class InterfaceWriterGSpec extends Specification {
2828

2929
void "writes 'package'" () {
3030
def pkg = 'com.github.hauner.openapi'
31-
def apiItf = new Interface ("", pkg, identifier)
31+
def apiItf = new Interface ("", pkg, identifier, null)
3232

3333
when:
3434
writer.write (target, apiItf)
@@ -42,7 +42,7 @@ package $pkg;
4242
}
4343

4444
void "writes @Generated import" () {
45-
def apiItf = new Interface ("", "", identifier)
45+
def apiItf = new Interface ("", "", identifier, null)
4646

4747
when:
4848
writer.write (target, apiItf)
@@ -54,7 +54,7 @@ import io.openapiprocessor.generated.support.Generated;
5454
}
5555

5656
void "writes 'interface' block" () {
57-
def apiItf = new Interface ('name', 'pkg', identifier)
57+
def apiItf = new Interface ('name', 'pkg', identifier, null)
5858

5959
when:
6060
writer.write (target, apiItf)

openapi-processor-core/src/test/kotlin/io/openapiprocessor/core/builder/api/InterfaceBuilder.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ fun `interface`(
1616
name: String = "Foo",
1717
pkg: String = "io.openapiprocessor.test",
1818
identifier: Identifier = JavaIdentifier(),
19+
path: String? = null,
1920
init: InterfaceBuilder.() -> Unit
2021
): Interface {
2122
val builder = InterfaceBuilder(name, pkg, identifier)
@@ -27,17 +28,19 @@ fun itf(
2728
name: String = "Foo",
2829
pkg: String = "io.openapiprocessor.test",
2930
identifier: Identifier = JavaIdentifier(),
31+
path: String? = null,
3032
init: InterfaceBuilder.() -> Unit
3133
): Interface {
32-
val builder = InterfaceBuilder(name, pkg, identifier)
34+
val builder = InterfaceBuilder(name, pkg, identifier, path)
3335
init(builder)
3436
return builder.build()
3537
}
3638

3739
class InterfaceBuilder(
3840
private val name: String,
3941
private val pkg: String,
40-
private val identifier: Identifier
42+
private val identifier: Identifier,
43+
private val path: String? = null
4144
) {
4245
private val endpoints = mutableListOf<Endpoint>()
4346

@@ -46,7 +49,7 @@ class InterfaceBuilder(
4649
}
4750

4851
fun build(): Interface {
49-
val itf = Interface(name, pkg, identifier)
52+
val itf = Interface(name, pkg, identifier, path)
5053
itf.add(*endpoints.toTypedArray())
5154
return itf
5255
}

openapi-processor-core/src/test/kotlin/io/openapiprocessor/core/support/TestFrameworkAnnotations.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55

66
package io.openapiprocessor.core.support
77

8+
import io.openapiprocessor.core.framework.AnnotationType
89
import io.openapiprocessor.core.framework.FrameworkAnnotations
910
import io.openapiprocessor.core.model.Annotation
1011
import io.openapiprocessor.core.model.parameters.Parameter
1112
import io.openapiprocessor.core.parser.HttpMethod
1213

1314
val MAPPING = Annotation("annotation.Mapping")
1415
val PARAMETER = Annotation("annotation.Parameter")
16+
val PREFIX = Annotation("annotation.Prefix")
1517

1618
/**
1719
* simple [io.openapiprocessor.core.framework.FrameworkAnnotations] implementation for testing.
@@ -25,4 +27,8 @@ class TestFrameworkAnnotations: FrameworkAnnotations {
2527
override fun getAnnotation(parameter: Parameter): Annotation {
2628
return PARAMETER
2729
}
30+
31+
override fun getAnnotation(type: AnnotationType): Annotation {
32+
return PREFIX
33+
}
2834
}

openapi-processor-core/src/test/kotlin/io/openapiprocessor/core/writer/java/InterfaceWriterSpec.kt

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import io.kotest.core.spec.style.StringSpec
1010
import io.kotest.matchers.collections.shouldContain
1111
import io.kotest.matchers.collections.shouldNotContain
1212
import io.kotest.matchers.shouldBe
13+
import io.kotest.matchers.string.shouldContain
1314
import io.mockk.every
1415
import io.openapiprocessor.core.builder.api.`interface`
1516
import io.openapiprocessor.core.builder.api.itf
1617
import io.openapiprocessor.core.converter.ApiOptions
1718
import io.openapiprocessor.core.converter.mapping.SimpleParameterValue
1819
import io.openapiprocessor.core.extractBody
1920
import io.openapiprocessor.core.extractImports
21+
import io.openapiprocessor.core.framework.AnnotationType
2022
import io.openapiprocessor.core.framework.FrameworkAnnotations
2123
import io.openapiprocessor.core.model.Annotation
2224
import io.openapiprocessor.core.model.Endpoint
@@ -478,6 +480,30 @@ class InterfaceWriterSpec: StringSpec({
478480

479481
writer.write(target, itf)
480482

481-
target.toString().contains("interface FooBar")
483+
target.toString() shouldContain "interface FooBar"
484+
}
485+
486+
"write server uri as path prefix" {
487+
every { annotations.getAnnotation(any<AnnotationType>()) } returns Annotation("annotation.Prefix")
488+
489+
val itf = itf("foo-bar", "api", path = "/prefix") {
490+
endpoint("/foo") {
491+
responses {
492+
status("200") {
493+
response("text/plain", StringDataType())
494+
}
495+
}
496+
}
497+
}
498+
499+
options.serverPrefix = true
500+
writer.write(target, itf)
501+
502+
target.toString() shouldContain "import annotation.Prefix;"
503+
504+
target.toString() shouldContain """
505+
|@Prefix("/prefix")
506+
|public interface FooBarApi"""
507+
.trimMargin()
482508
}
483509
})

openapi-processor-core/src/testInt/kotlin/io/openapiprocessor/core/TestFrameworkAnnotations.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55

66
package io.openapiprocessor.core
77

8+
import io.openapiprocessor.core.framework.AnnotationType
89
import io.openapiprocessor.core.framework.FrameworkAnnotations
910
import io.openapiprocessor.core.model.Annotation
1011
import io.openapiprocessor.core.model.parameters.Parameter
1112
import io.openapiprocessor.core.parser.HttpMethod
1213

1314
val MAPPING = Annotation("annotation.Mapping")
1415
val PARAMETER = Annotation("annotation.Parameter")
16+
val PREFIX = Annotation("annotation.Prefix")
1517

1618
/**
1719
* simple [io.openapiprocessor.core.framework.FrameworkAnnotations] implementation for testing.
@@ -25,4 +27,8 @@ class TestFrameworkAnnotations: FrameworkAnnotations {
2527
override fun getAnnotation(parameter: Parameter): Annotation {
2628
return PARAMETER
2729
}
30+
31+
override fun getAnnotation(type: AnnotationType): Annotation {
32+
return PREFIX
33+
}
2834
}

0 commit comments

Comments
 (0)