Skip to content

Commit 09a5074

Browse files
committed
Make ExposedThingBuilder able to handle link annotations.
1 parent f02a15b commit 09a5074

File tree

9 files changed

+72
-2
lines changed

9 files changed

+72
-2
lines changed

kotlin-wot-integration-tests/src/main/kotlin/integration/ChatAgent.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import org.springframework.stereotype.Component
2525
@Thing(id="chatagent", title="Chat Agent",
2626
description="A chat agent.", type= LMOSThingType.AGENT)
2727
@Context(prefix = LMOSContext.prefix, url = LMOSContext.url)
28+
@Link(href = "lmos/capabilities", rel = "service-meta", type = "application/json")
2829
@VersionInfo(instance = "1.0.0")
2930
@Component
3031
class ChatAgent(agentProvider: AgentProvider, @Property(readOnly = true)

kotlin-wot-reflection/src/main/kotlin/reflection/ExposedThingBuilder.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import ai.ancf.lmos.wot.JsonMapper
44
import ai.ancf.lmos.wot.Wot
55
import ai.ancf.lmos.wot.reflection.annotations.*
66
import ai.ancf.lmos.wot.reflection.annotations.Context
7+
import ai.ancf.lmos.wot.reflection.annotations.Link
78
import ai.ancf.lmos.wot.reflection.annotations.VersionInfo
89
import ai.ancf.lmos.wot.thing.DEFAULT_CONTEXT
910
import ai.ancf.lmos.wot.thing.ExposedThing
@@ -77,6 +78,26 @@ object ExposedThingBuilder {
7778
if(versionInfoAnnotation != null){
7879
version = ai.ancf.lmos.wot.thing.schema.VersionInfo(versionInfoAnnotation.instance, versionInfoAnnotation.model)
7980
}
81+
clazz.findAnnotation<Link>()?.let { linkAnnotation ->
82+
links.add(ai.ancf.lmos.wot.thing.schema.Link(
83+
href = linkAnnotation.href,
84+
type = linkAnnotation.type,
85+
rel = linkAnnotation.rel,
86+
anchor = linkAnnotation.anchor,
87+
sizes = linkAnnotation.sizes,
88+
hreflang = linkAnnotation.hreflang.toList()
89+
))
90+
}
91+
clazz.findAnnotation<Links>()?.values?.forEach { linkAnnotation ->
92+
links.add(ai.ancf.lmos.wot.thing.schema.Link(
93+
href = linkAnnotation.href,
94+
type = linkAnnotation.type,
95+
rel = linkAnnotation.rel,
96+
anchor = linkAnnotation.anchor,
97+
sizes = linkAnnotation.sizes,
98+
hreflang = linkAnnotation.hreflang.toList()
99+
))
100+
}
80101
// 3. Inspect the properties of the class and find @Property annotations
81102
clazz.memberProperties.forEach { property ->
82103
val propertyAnnotation = property.findAnnotation<Property>()

kotlin-wot-reflection/src/main/kotlin/reflection/annotations/Annotations.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,21 @@ annotation class Context(val prefix: String, val url : String)
1515
@Retention(AnnotationRetention.RUNTIME)
1616
annotation class VersionInfo(val instance : String, val model : String = "")
1717

18+
@Target(AnnotationTarget.CLASS)
19+
@Retention(AnnotationRetention.RUNTIME)
20+
annotation class Link(
21+
val href: String,
22+
val type: String = "",
23+
val rel: String = "",
24+
val anchor: String = "",
25+
val sizes: String = "",
26+
val hreflang: Array<String> = []
27+
)
28+
29+
@Target(AnnotationTarget.CLASS)
30+
@Retention(AnnotationRetention.RUNTIME)
31+
annotation class Links(val values: Array<Link>)
32+
1833
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE_PARAMETER)
1934
@Retention(AnnotationRetention.RUNTIME)
2035
annotation class Property(val title: String = "", val description: String = "", val readOnly: Boolean = false, val writeOnly: Boolean = false)

kotlin-wot-reflection/src/test/kotlin/reflection/ComplexThingTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class ComplexThingTest {
3535
assertEquals("Complex Thing", thingDescription.title, "ThingDescription title should match")
3636
assertEquals("A thing with complex properties, actions, and events.", thingDescription.description, "ThingDescription description should match")
3737
assertEquals("1.0.0", thingDescription.version?.instance)
38+
assertEquals(listOf(Link("my/link", "my/type", "my-rel", "my-anchor", "my-sizes", listOf("my-lang-1", "my-lang-2"))), thingDescription.links)
3839
}
3940

4041
@Test

kotlin-wot-reflection/src/test/kotlin/reflection/SimpleThingTest.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import ai.ancf.lmos.wot.content.toJsonContent
88
import ai.ancf.lmos.wot.reflection.things.SimpleThing
99
import ai.ancf.lmos.wot.thing.ExposedThing
1010
import ai.ancf.lmos.wot.thing.schema.ContentListener
11+
import ai.ancf.lmos.wot.thing.schema.Link
1112
import ai.ancf.lmos.wot.thing.schema.StringSchema
13+
import ai.ancf.lmos.wot.thing.schema.WoTThingDescription
1214
import kotlinx.coroutines.runBlocking
1315
import kotlinx.coroutines.test.runTest
1416
import java.util.concurrent.CountDownLatch
@@ -21,6 +23,7 @@ class SimpleThingTest {
2123
lateinit var wot: Wot
2224
lateinit var simpleThing: SimpleThing
2325
lateinit var exposedThing: ExposedThing
26+
lateinit var thingDescription: WoTThingDescription
2427

2528
@BeforeTest
2629
fun setUp() = runTest {
@@ -35,11 +38,22 @@ class SimpleThingTest {
3538

3639
// Generate ThingDescription from the class
3740
exposedThing = ExposedThingBuilder.createExposedThing(wot, simpleThing, SimpleThing::class) as ExposedThing
41+
thingDescription = exposedThing.getThingDescription()
3842

3943
servient.addThing(exposedThing)
4044
servient.expose("simpleThing")
4145
}
4246

47+
@Test
48+
fun `test ThingDescription creation for SimpleThing`() {
49+
// Validate Thing metadata
50+
assertEquals("simpleThing", thingDescription.id, "ThingDescription ID should match the class ID")
51+
assertEquals("Simple Thing", thingDescription.title, "ThingDescription title should match")
52+
assertEquals("A thing with complex properties, actions, and events.", thingDescription.description, "ThingDescription description should match")
53+
assertEquals("1.0.0", thingDescription.version?.instance)
54+
assertEquals(listOf(Link("my/link", "my/type", "my-rel", "my-anchor", "my-sizes", listOf("my-lang-1", "my-lang-2"))), thingDescription.links)
55+
}
56+
4357
@Test
4458
fun `Read mutable property`() = runTest {
4559
val content = exposedThing.handleReadProperty("mutableProperty")

kotlin-wot-reflection/src/test/kotlin/reflection/things/ComplexThing.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ import kotlin.random.Random
1313
title = "Complex Thing",
1414
description = "A thing with complex properties, actions, and events."
1515
)
16+
@Links(
17+
values = [Link(
18+
href = "my/link",
19+
rel = "my-rel",
20+
type = "my/type",
21+
anchor = "my-anchor",
22+
sizes = "my-sizes",
23+
hreflang = ["my-lang-1", "my-lang-2"]
24+
)]
25+
)
1626
@VersionInfo(instance = "1.0.0")
1727
class ComplexThing(@Property(readOnly = true) val constructorProperty: String = "Hello World") {
1828

kotlin-wot-reflection/src/test/kotlin/reflection/things/SimpleThing.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ import kotlinx.coroutines.flow.flow
1010
title = "Simple Thing",
1111
description = "A thing with complex properties, actions, and events."
1212
)
13+
@Link(
14+
href = "my/link",
15+
rel = "my-rel",
16+
type = "my/type",
17+
anchor = "my-anchor",
18+
sizes = "my-sizes",
19+
hreflang = ["my-lang-1", "my-lang-2"]
20+
)
1321
@VersionInfo(instance = "1.0.0")
1422
class SimpleThing {
1523

kotlin-wot/src/main/kotlin/thing/ThingDescription.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ data class ThingDescription @JsonCreator constructor(
7474
@JsonInclude(NON_EMPTY) override var created: String? = null,
7575
@JsonInclude(NON_EMPTY) override var modified: String? = null,
7676
@JsonInclude(NON_EMPTY) override var support: String? = null,
77-
@JsonInclude(NON_EMPTY) override var links: List<Link>? = null,
77+
@JsonInclude(NON_EMPTY) override var links: MutableList<Link> = mutableListOf(),
7878
@JsonFormat(with = [JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY]) @JsonInclude(NON_EMPTY) override var profile: List<String>? = null,
7979
@JsonInclude(NON_EMPTY) override var schemaDefinitions: MutableMap<String, DataSchema<Any>>? = null,
8080
@JsonInclude(NON_EMPTY) override var uriVariables: MutableMap<String, DataSchema<Any>>? = null

kotlin-wot/src/main/kotlin/thing/schema/WoTThingDescription.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ interface WoTThingDescription : BaseSchema {
103103
* @return an array of links.
104104
*/
105105
@get:JsonInclude(JsonInclude.Include.NON_EMPTY)
106-
var links: List<Link>? // Optional: Array of Link
106+
var links: MutableList<Link> // Optional: Array of Link
107107

108108
/**
109109
* Set of form hypermedia controls that describe how an operation can be performed.

0 commit comments

Comments
 (0)