diff --git a/README.md b/README.md index 14e484f0a..d5844bc72 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ fun sampleOrder() { * @[sangy515](https://github.com/sangy515) * @[yunseok-jeong0](https://github.com/yunseok-jeong0) * @[wicksome](https://github.com/wicksome) -* @[Wonjin Choi](https://github.com/jinia91) +* @[jinia91](https://github.com/jinia91) * @[songkg7](https://github.com/songkg7) * @[this-is-spear](https://github.com/this-is-spear) * @[donggyunhuh](https://github.com/donggyunhuh) diff --git a/docs/content/v1.0.x/docs/plugins/kotlin-plugin/introspectors-for-kotlin.md b/docs/content/v1.0.x/docs/plugins/kotlin-plugin/introspectors-for-kotlin.md index fb5b7bd7e..3bb891e21 100644 --- a/docs/content/v1.0.x/docs/plugins/kotlin-plugin/introspectors-for-kotlin.md +++ b/docs/content/v1.0.x/docs/plugins/kotlin-plugin/introspectors-for-kotlin.md @@ -41,3 +41,74 @@ fun test() { val product: Product = fixtureMonkey.giveMeOne() } ``` + +## KotlinAndJavaCompositeArbitraryIntrospector + +The `KotlinAndJavaCompositeArbitraryIntrospector` is an introspector designed to assist in the creation of Kotlin classes that reference Java classes. + + +**Example Kotlin Class :** +```kotlin +class KotlinClassWithJavaClass(val javaObject: JavaObject) +``` + +**Example Java Class :** +```java +public class JavaObject { + private String value; + private Map map; + + public JavaObject() { + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } +} +``` + +**Using PrimaryConstructorArbitraryIntrospector :** +```kotlin + fun kotlinClassWithJavaClass() { + // given + val sut: FixtureMonkey = FixtureMonkey.builder() + .plugin(KotlinPlugin()) + .objectIntrospector(KotlinAndJavaCompositeArbitraryIntrospector()) + .build() + + // when + val actual = sut.giveMeOne() + + then(actual).isNotNull + then(actual.javaObject).isNotNull + } +``` + +For Kotlin and Java classes respectively, it uses the PrimaryConstructorArbitraryIntrospector and the BeanArbitraryIntrospector by default. + +If changes are desired, these can be injected as arguments. + +```kotlin + // given + val sut: FixtureMonkey = FixtureMonkey.builder() + .plugin(KotlinPlugin()) + .objectIntrospector( + KotlinAndJavaCompositeArbitraryIntrospector( + kotlinArbitraryIntrospector = PrimaryConstructorArbitraryIntrospector.INSTANCE, + javaArbitraryIntrospector = ConstructorPropertiesArbitraryIntrospector.INSTANCE + ) + ) + .build() +``` diff --git a/fixture-monkey-benchmarks/fixture-monkey-benchmark-kotlin/src/jmh/kotlin/com/navercorp/fixturemonkey/kotlin/KotlinJavaCompositeOrderSheet.kt b/fixture-monkey-benchmarks/fixture-monkey-benchmark-kotlin/src/jmh/kotlin/com/navercorp/fixturemonkey/kotlin/KotlinJavaCompositeOrderSheet.kt new file mode 100644 index 000000000..6b3d24049 --- /dev/null +++ b/fixture-monkey-benchmarks/fixture-monkey-benchmark-kotlin/src/jmh/kotlin/com/navercorp/fixturemonkey/kotlin/KotlinJavaCompositeOrderSheet.kt @@ -0,0 +1,34 @@ +package com.navercorp.fixturemonkey.kotlin + +import com.navercorp.fixturemonkey.OrderSheet +import java.math.BigDecimal +import java.time.Instant +import javax.validation.constraints.Size + +data class KotlinJavaCompositeOrderSheet( + val id: String, + val backUrl: String?, + val userNo: Long?, + @field:Size(min = 1, max = 1) + val products: List, + val merchantsByMerchantNo: Map.Entry?, + val registeredDateTime: Instant?, + @field:Size(min = 1, max = 1) + val bundleDeliveryFeesByDeliveryGroupKey: Map? +) { + data class OrderSheetMerchant( + val talkInterlockAccountId: String?, + val logeyeRequestId: String?, + val logeyeInflowPathName: String?, + val logeyePayAccumulation: Boolean? + ) + + data class OrderSheetBundleDeliveryFee( + val deliveryFee: BigDecimal?, + val type: BundleType + ) + + enum class BundleType { + MANUALLY, IDENTICAL_PRODUCT + } +} diff --git a/fixture-monkey-benchmarks/fixture-monkey-benchmark-kotlin/src/jmh/kotlin/com/navercorp/fixturemonkey/kotlin/KotlinObjectGenerationBenchMark.kt b/fixture-monkey-benchmarks/fixture-monkey-benchmark-kotlin/src/jmh/kotlin/com/navercorp/fixturemonkey/kotlin/KotlinObjectGenerationBenchMark.kt index c4933626f..c31201273 100644 --- a/fixture-monkey-benchmarks/fixture-monkey-benchmark-kotlin/src/jmh/kotlin/com/navercorp/fixturemonkey/kotlin/KotlinObjectGenerationBenchMark.kt +++ b/fixture-monkey-benchmarks/fixture-monkey-benchmark-kotlin/src/jmh/kotlin/com/navercorp/fixturemonkey/kotlin/KotlinObjectGenerationBenchMark.kt @@ -4,6 +4,7 @@ import com.navercorp.fixturemonkey.OrderSheet import com.navercorp.fixturemonkey.FixtureMonkey import com.navercorp.fixturemonkey.api.introspector.BeanArbitraryIntrospector import com.navercorp.fixturemonkey.api.type.TypeCache +import com.navercorp.fixturemonkey.kotlin.introspector.KotlinAndJavaCompositeArbitraryIntrospector import java.util.concurrent.TimeUnit import org.openjdk.jmh.annotations.Benchmark import org.openjdk.jmh.annotations.BenchmarkMode @@ -48,4 +49,16 @@ open class KotlinObjectGenerationBenchMark { private fun generateKotlinOrderSheet(fixtureMonkey: FixtureMonkey): List = List(COUNT) { fixtureMonkey.giveMeOne(KotlinOrderSheet::class.java) } + + @Benchmark + fun beanGenerateKotlinJavaCompositeOrderSheetWithFixtureMonkey(blackhole: Blackhole) { + val fixtureMonkey = FixtureMonkey.builder() + .plugin(KotlinPlugin()) + .objectIntrospector(KotlinAndJavaCompositeArbitraryIntrospector()) + .build() + blackhole.consume(generateKotlinJavaCompositeOrderSheet(fixtureMonkey)) + } + + private fun generateKotlinJavaCompositeOrderSheet(fixtureMonkey: FixtureMonkey): List = + List(COUNT) { fixtureMonkey.giveMeOne(KotlinJavaCompositeOrderSheet::class.java) } } diff --git a/fixture-monkey-kotlin/src/main/kotlin/com/navercorp/fixturemonkey/kotlin/introspector/KotlinAndJavaCompositeArbitraryIntrospector.kt b/fixture-monkey-kotlin/src/main/kotlin/com/navercorp/fixturemonkey/kotlin/introspector/KotlinAndJavaCompositeArbitraryIntrospector.kt new file mode 100644 index 000000000..e01b51567 --- /dev/null +++ b/fixture-monkey-kotlin/src/main/kotlin/com/navercorp/fixturemonkey/kotlin/introspector/KotlinAndJavaCompositeArbitraryIntrospector.kt @@ -0,0 +1,50 @@ +/* + * Fixture Monkey + * + * Copyright (c) 2021-present NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.fixturemonkey.kotlin.introspector + +import com.navercorp.fixturemonkey.api.generator.ArbitraryGeneratorContext +import com.navercorp.fixturemonkey.api.introspector.ArbitraryIntrospector +import com.navercorp.fixturemonkey.api.introspector.ArbitraryIntrospectorResult +import com.navercorp.fixturemonkey.api.introspector.BeanArbitraryIntrospector +import com.navercorp.fixturemonkey.kotlin.type.actualType +import com.navercorp.fixturemonkey.kotlin.type.isKotlinType +import org.slf4j.LoggerFactory + +class KotlinAndJavaCompositeArbitraryIntrospector( + private val kotlinArbitraryIntrospector: ArbitraryIntrospector = PrimaryConstructorArbitraryIntrospector.INSTANCE, + private val javaArbitraryIntrospector: ArbitraryIntrospector = BeanArbitraryIntrospector.INSTANCE, +) : ArbitraryIntrospector { + override fun introspect(context: ArbitraryGeneratorContext): ArbitraryIntrospectorResult { + val type = context.resolvedType.actualType() + try { + return if (type.isKotlinType()) { + kotlinArbitraryIntrospector.introspect(context) + } else { + javaArbitraryIntrospector.introspect(context) + } + } catch (e: Exception) { + LOGGER.warn("Given type $type is failed to generated due to the exception.", e) + return ArbitraryIntrospectorResult.NOT_INTROSPECTED + } + } + + companion object { + private val LOGGER = LoggerFactory.getLogger(KotlinAndJavaCompositeArbitraryIntrospector::class.java) + } +} diff --git a/fixture-monkey-kotlin/src/test/kotlin/com/navercorp/fixturemonkey/kotlin/test/KotlinAndJavaCompositeArbitraryIntrospectorTest.kt b/fixture-monkey-kotlin/src/test/kotlin/com/navercorp/fixturemonkey/kotlin/test/KotlinAndJavaCompositeArbitraryIntrospectorTest.kt new file mode 100644 index 000000000..bfd959b4f --- /dev/null +++ b/fixture-monkey-kotlin/src/test/kotlin/com/navercorp/fixturemonkey/kotlin/test/KotlinAndJavaCompositeArbitraryIntrospectorTest.kt @@ -0,0 +1,78 @@ +/* + * Fixture Monkey + * + * Copyright (c) 2021-present NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.fixturemonkey.kotlin.test + +import com.navercorp.fixturemonkey.FixtureMonkey +import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector +import com.navercorp.fixturemonkey.kotlin.KotlinPlugin +import com.navercorp.fixturemonkey.kotlin.giveMeOne +import com.navercorp.fixturemonkey.kotlin.introspector.KotlinAndJavaCompositeArbitraryIntrospector +import net.jqwik.api.Property +import org.assertj.core.api.BDDAssertions.then + +class KotlinAndJavaCompositeArbitraryIntrospectorTest { + @Property + fun kotlinClassWithJavaClass() { + // given + val sut: FixtureMonkey = FixtureMonkey.builder() + .plugin(KotlinPlugin()) + .objectIntrospector(KotlinAndJavaCompositeArbitraryIntrospector()) + .build() + + // when + val actual = sut.giveMeOne() + + then(actual).isNotNull + then(actual.javaObject).isNotNull + } + + @Property + fun kotlinClassWithJavaClassUsingOtherIntrospector() { + // given + val sut: FixtureMonkey = FixtureMonkey.builder() + .plugin(KotlinPlugin()) + .objectIntrospector( + KotlinAndJavaCompositeArbitraryIntrospector( + javaArbitraryIntrospector = ConstructorPropertiesArbitraryIntrospector.INSTANCE + ) + ) + .build() + + // when + val actual = sut.giveMeOne() + + then(actual).isNotNull + then(actual.javaObject).isNotNull + } + + @Property + fun sampleMapValue() { + // given + val sut: FixtureMonkey = FixtureMonkey.builder() + .plugin(KotlinPlugin()) + .objectIntrospector(KotlinAndJavaCompositeArbitraryIntrospector()) + .build() + + // when + val actual = sut.giveMeOne() + + then(actual).isNotNull + then(actual.map).isNotNull + } +} diff --git a/fixture-monkey-kotlin/src/test/kotlin/com/navercorp/fixturemonkey/kotlin/test/KotlinAndJavaCompositeArbitraryIntrospectorTestSpecs.kt b/fixture-monkey-kotlin/src/test/kotlin/com/navercorp/fixturemonkey/kotlin/test/KotlinAndJavaCompositeArbitraryIntrospectorTestSpecs.kt new file mode 100644 index 000000000..644883e98 --- /dev/null +++ b/fixture-monkey-kotlin/src/test/kotlin/com/navercorp/fixturemonkey/kotlin/test/KotlinAndJavaCompositeArbitraryIntrospectorTestSpecs.kt @@ -0,0 +1,25 @@ +/* + * Fixture Monkey + * + * Copyright (c) 2021-present NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.fixturemonkey.kotlin.test + +import com.navercorp.fixturemonkey.kotlin.spec.JavaObject + +class KotlinClassWithJavaClass(val javaObject: JavaObject) + +class MapValue(val map: Map)