Skip to content

Commit 8f93ca2

Browse files
committed
finalize
1 parent 9891a33 commit 8f93ca2

File tree

4 files changed

+196
-113
lines changed

4 files changed

+196
-113
lines changed

README.md

Lines changed: 112 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ And you will have to include the required dependencies:
2828

2929
```groovy
3030
dependencies {
31-
implementation 'com.github.tobrun.kotlin-data-compat:annotation:0.5.2'
32-
ksp 'com.github.tobrun.kotlin-data-compat:processor:0.5.2'
31+
implementation 'com.github.tobrun.kotlin-data-compat:annotation:0.6.0'
32+
ksp 'com.github.tobrun.kotlin-data-compat:processor:0.6.0'
3333
}
3434
```
3535

@@ -44,10 +44,14 @@ Given an exisiting data class:
4444
- support imports for default parameters
4545
- retain existing class annotations (but not parameters for them)
4646
- retain existing interfaces
47+
- make non-nullable parameters without defaults mandatory Builder constructor parameters
4748

4849
For example:
4950

5051
```kotlin
52+
import com.tobrun.datacompat.annotation.DataCompat
53+
import com.tobrun.datacompat.annotation.Default
54+
5155
interface SampleInterface
5256
annotation class SampleAnnotation
5357

@@ -67,19 +71,31 @@ private data class PersonData(
6771
*/
6872
val nickname: String?,
6973
@Default("42")
70-
val age: Int
74+
val age: Int,
75+
@Default("50.2f")
76+
val euroAmount: Float,
77+
@Default("300.0")
78+
val dollarAmount: Double?,
79+
/**
80+
* Extra info. Mandatory property.
81+
*/
82+
val extraInfo: String,
7183
) : SampleInterface
7284
```
7385

7486
After compilation, the following class will be generated:
7587

7688
```kotlin
89+
@file:Suppress("RedundantVisibilityModifier")
90+
7791
package com.tobrun.`data`.compat.example
7892

7993
import java.util.Date
8094
import java.util.Objects
8195
import kotlin.Any
8296
import kotlin.Boolean
97+
import kotlin.Double
98+
import kotlin.Float
8399
import kotlin.Int
84100
import kotlin.String
85101
import kotlin.Unit
@@ -94,24 +110,35 @@ import kotlin.jvm.JvmSynthetic
94110
@SampleAnnotation
95111
public class Person private constructor(
96112
/**
97-
* The full name.
113+
* Name.
98114
*/
99115
public val name: String,
100116
/**
101-
* The nickname.
102117
* Additional comment.
103118
*/
104119
public val nickname: String?,
105120
/**
106-
* The age.
121+
* Age.
122+
*/
123+
public val age: Int,
124+
/**
125+
* Euro amount.
107126
*/
108-
public val age: Int
127+
public val euroAmount: Float,
128+
/**
129+
* Dollar amount.
130+
*/
131+
public val dollarAmount: Double?,
132+
/**
133+
* Extra info. Mandatory property.
134+
*/
135+
public val extraInfo: String
109136
) : SampleInterface {
110137
/**
111138
* Overloaded toString function.
112139
*/
113-
public override fun toString() = """Person(name=$name, nickname=$nickname,
114-
age=$age)""".trimIndent()
140+
public override fun toString() = """Person(name=$name, nickname=$nickname, age=$age,
141+
euroAmount=$euroAmount, dollarAmount=$dollarAmount, extraInfo=$extraInfo)""".trimIndent()
115142

116143
/**
117144
* Overloaded equals function.
@@ -120,64 +147,82 @@ public class Person private constructor(
120147
if (this === other) return true
121148
if (javaClass != other?.javaClass) return false
122149
other as Person
123-
return name == other.name && nickname == other.nickname && age == other.age
150+
return name == other.name && nickname == other.nickname && age == other.age &&
151+
euroAmount.compareTo(other.euroAmount) == 0 &&
152+
(dollarAmount ?: 0.0).compareTo(other.dollarAmount ?: 0.0) == 0 &&
153+
extraInfo == other.extraInfo
124154
}
125155

126156
/**
127157
* Overloaded hashCode function based on all class properties.
128158
*/
129-
public override fun hashCode(): Int = Objects.hash(name, nickname, age)
159+
public override fun hashCode(): Int = Objects.hash(name, nickname, age, euroAmount, dollarAmount,
160+
extraInfo)
130161

131162
/**
132163
* Convert to Builder allowing to change class properties.
133164
*/
134-
public fun toBuilder(): Builder = Builder() .setName(name) .setNickname(nickname) .setAge(age)
165+
public fun toBuilder(): Builder = Builder(extraInfo) .setName(name) .setNickname(nickname)
166+
.setAge(age) .setEuroAmount(euroAmount) .setDollarAmount(dollarAmount)
167+
.setExtraInfo(extraInfo)
135168

136169
/**
137170
* Composes and builds a [Person] object.
138171
*
139172
* This is a concrete implementation of the builder design pattern.
140-
*
141-
* @property name The full name.
142-
* @property nickname The nickname.
143-
* @property age The age.
144173
*/
145-
public class Builder {
174+
public class Builder(
146175
/**
147-
* The full name.
176+
* Extra info. Mandatory property.
148177
*/
149178
@set:JvmSynthetic
150-
public var name: String? = "John" + Date(1580897313933L).toString()
179+
public var extraInfo: String
180+
) {
181+
/**
182+
* Name.
183+
*/
184+
@set:JvmSynthetic
185+
public var name: String = "John" + Date(1580897313933L).toString()
151186

152187
/**
153-
* The nickname.
154188
* Additional comment.
155189
*/
156190
@set:JvmSynthetic
157191
public var nickname: String? = null
158192

159193
/**
160-
* The age.
194+
* Age.
195+
*/
196+
@set:JvmSynthetic
197+
public var age: Int = 42
198+
199+
/**
200+
* Euro amount.
161201
*/
162202
@set:JvmSynthetic
163-
public var age: Int? = 42
203+
public var euroAmount: Float = 50.2f
164204

165205
/**
166-
* Set the full name.
206+
* Dollar amount.
207+
*/
208+
@set:JvmSynthetic
209+
public var dollarAmount: Double? = 300.0
210+
211+
/**
212+
* Setter for name: name.
167213
*
168-
* @param name the full name.
214+
* @param name
169215
* @return Builder
170216
*/
171-
public fun setName(name: String?): Builder {
217+
public fun setName(name: String): Builder {
172218
this.name = name
173219
return this
174220
}
175221

176222
/**
177-
* Set the nickname.
178-
* Additional comment.
223+
* Setter for nickname: additional comment.
179224
*
180-
* @param nickname the nickname.
225+
* @param nickname
181226
* @return Builder
182227
*/
183228
public fun setNickname(nickname: String?): Builder {
@@ -186,32 +231,55 @@ public class Person private constructor(
186231
}
187232

188233
/**
189-
* Set the age.
234+
* Setter for age: age.
190235
*
191-
* @param age the age.
236+
* @param age
192237
* @return Builder
193238
*/
194-
public fun setAge(age: Int?): Builder {
239+
public fun setAge(age: Int): Builder {
195240
this.age = age
196241
return this
197242
}
198243

199244
/**
200-
* Returns a [Person] reference to the object being constructed by the builder.
245+
* Setter for euroAmount: euro amount.
201246
*
202-
* Throws an [IllegalArgumentException] when a non-null property wasn't initialised.
247+
* @param euroAmount
248+
* @return Builder
249+
*/
250+
public fun setEuroAmount(euroAmount: Float): Builder {
251+
this.euroAmount = euroAmount
252+
return this
253+
}
254+
255+
/**
256+
* Setter for dollarAmount: dollar amount.
203257
*
204-
* @return Person
258+
* @param dollarAmount
259+
* @return Builder
205260
*/
206-
public fun build(): Person {
207-
if (name==null) {
208-
throw IllegalArgumentException("""Null name found when building Person.""".trimIndent())
209-
}
210-
if (age==null) {
211-
throw IllegalArgumentException("""Null age found when building Person.""".trimIndent())
212-
}
213-
return Person(name!!, nickname, age!!)
261+
public fun setDollarAmount(dollarAmount: Double?): Builder {
262+
this.dollarAmount = dollarAmount
263+
return this
214264
}
265+
266+
/**
267+
* Setter for extraInfo: extra info. Mandatory property.
268+
*
269+
* @param extraInfo
270+
* @return Builder
271+
*/
272+
public fun setExtraInfo(extraInfo: String): Builder {
273+
this.extraInfo = extraInfo
274+
return this
275+
}
276+
277+
/**
278+
* Returns a [Person] reference to the object being constructed by the builder.
279+
*
280+
* @return Person
281+
*/
282+
public fun build(): Person = Person(name, nickname, age, euroAmount, dollarAmount, extraInfo)
215283
}
216284
}
217285

@@ -222,6 +290,6 @@ public class Person private constructor(
222290
* @return Person
223291
*/
224292
@JvmSynthetic
225-
public fun Person(initializer: Person.Builder.() -> Unit): Person =
226-
Person.Builder().apply(initializer).build()
293+
public fun Person(extraInfo: String, initializer: Person.Builder.() -> Unit): Person =
294+
Person.Builder(extraInfo).apply(initializer).build()
227295
```

processor/src/main/kotlin/com/tobrun/datacompat/DataCompatProcessor.kt

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -231,21 +231,22 @@ class DataCompatProcessor(
231231
prefix = "return ",
232232
separator = "·&& ",
233233
transform = {
234-
val resolvedType = it.type.resolve()
235-
val isFloat =
236-
resolvedType.toClassName() == Float::class.asTypeName()
237-
val isDouble =
238-
resolvedType.toClassName() == Double::class.asTypeName()
239-
if (isFloat || isDouble) {
240-
if (resolvedType.isMarkedNullable && isDouble) {
241-
"($it·?:·0.0).compareTo(other.$it·?:·0.0)·==·0"
242-
} else if (resolvedType.isMarkedNullable && isFloat) {
243-
"($it·?:·0f).compareTo(other.$it·?:·0f)·==·0"
234+
with(it.type.resolve()) {
235+
val isFloat =
236+
toClassName() == Float::class.asTypeName()
237+
val isDouble =
238+
toClassName() == Double::class.asTypeName()
239+
if (isFloat || isDouble) {
240+
if (isMarkedNullable && isDouble) {
241+
"($it·?:·0.0).compareTo(other.$it·?:·0.0)·==·0"
242+
} else if (isMarkedNullable && isFloat) {
243+
"($it·?:·0f).compareTo(other.$it·?:·0f)·==·0"
244+
} else {
245+
"$it.compareTo(other.$it)·==·0"
246+
}
244247
} else {
245-
"$it.compareTo(other.$it)·==·0"
248+
"$it·==·other.$it"
246249
}
247-
} else {
248-
"$it·==·other.$it"
249250
}
250251
},
251252
postfix = ""
@@ -432,16 +433,15 @@ class DataCompatProcessor(
432433
}
433434

434435
initializerFunctionBuilder.addParameter(
435-
ParameterSpec.builder(
436-
"initializer",
437-
LambdaTypeName.get(
438-
ClassName(packageName, className, "Builder"),
439-
emptyList(),
440-
ClassName("kotlin", "Unit")
441-
)
442-
).build()
443-
)
444-
.addStatement("return $className.Builder($mandatoryParams).apply(initializer).build()")
436+
ParameterSpec.builder(
437+
"initializer",
438+
LambdaTypeName.get(
439+
ClassName(packageName, className, "Builder"),
440+
emptyList(),
441+
ClassName("kotlin", "Unit")
442+
)
443+
).build()
444+
).addStatement("return $className.Builder($mandatoryParams).apply(initializer).build()")
445445

446446
// File
447447
val fileBuilder = FileSpec.builder(packageName, className)

processor/src/test/kotlin/com/tobrun/datacompat/DataCompatProcessorTest.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ private data class PersonData(
3737
/**
3838
* Actually it's a very short description.
3939
*/
40-
val veryLongAndVeryDetailedDescription: String?
40+
val veryLongAndVeryDetailedDescription: String?,
41+
/**
42+
* Parameter that will become constructor parameter.
43+
*/
44+
val mandatoryDoubleWithoutDefault: Double,
4145
) : EmptyInterface, EmptyInterface2
4246
""".trimIndent()
4347
)

0 commit comments

Comments
 (0)