Reflective extensions code dump
Open
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 542
- Forks
- 101
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 2
Description
Talked offline, here's a dump of reflective extensions we currently employ because 🙃
package com.uber.thriftyextensions
import com.microsoft.thrifty.schema.Field
import com.microsoft.thrifty.schema.Location
import com.microsoft.thrifty.schema.Requiredness
import com.microsoft.thrifty.schema.UserElement
import com.microsoft.thrifty.schema.UserType
import com.microsoft.thrifty.schema.parser.ConstValueElement
import com.microsoft.thrifty.schema.parser.FieldElement
import java.lang.reflect.Modifier
import java.util.UUID
/*
* Unsafe reflection-based extensions to Thrifty's APIs. Necessary because there's no APIs available
* for adjusting [FieldElement] APIs.
*/
/**
* Creates a new copy of this [Field] with `required` [Field.required]ness reflectively set via its
* internal [FieldElement] field.
*
* @receiver the source [Field] to use. A defensive copy will be made.
* @return the new [Field] instance.
*/
fun Field.makeRequired(): Field {
val newElement = (elementField.get(this) as FieldElement).copy(requiredness = Requiredness.REQUIRED)
return toBuilder().build()
.apply {
elementField.set(this, newElement)
}
}
/**
* Creates a new copy of this [Field] with `optional` [Field.required]ness reflectively set via its
* internal [FieldElement] field.
*
* @receiver the source [Field] to use. A defensive copy will be made.
* @return the new [Field] instance.
*/
fun Field.makeOptional(): Field {
val newElement = (elementField.get(this) as FieldElement).copy(requiredness = Requiredness.OPTIONAL)
return toBuilder().build()
.apply {
elementField.set(this, newElement)
}
}
/**
* Creates a new copy of this [Field] with the specified [value] default value reflectively set via
* its internal [FieldElement] field.
*
* @receiver the source [Field] to use. A defensive copy will be made.
* @return the new [Field] instance.
*/
fun Field.withDefaultValue(value: ConstValueElement): Field {
val newElement = (elementField.get(this) as FieldElement).copy(constValue = value)
return toBuilder().build()
.apply {
elementField.set(this, newElement)
}
}
/**
* Creates a new copy of this [Field] with the specified [newId] reflectively set via its internal
* [FieldElement] field.
*
* @param newId the new id to set.
* @receiver the source [Field] to use. A defensive copy will be made.
* @return the new [Field] instance.
*/
fun Field.newId(newId: Int): Field {
val newElement = (elementField.get(this) as FieldElement).copy(fieldId = newId)
return toBuilder().build()
.apply {
elementField.set(this, newElement)
}
}
/**
* Ensures [this] list of [Field]s are valid (such as ensuring they've got unique field IDs).
*
* @param ensuredLocation the [Location] of the element holding this list to ensure fields match it.
* @receiver the source list to check. A defensive new copy will be made.
* @return the new fields list with the new field appended to the end.
*/
fun List<Field>.asSafeFields(ensuredLocation: Location): List<Field> {
if (distinctBy { it.id }.size == size) {
// They're all distinct, just return them with locations ensured
return map {
it.toBuilder()
.location(it.location.matchTo(ensuredLocation))
.build()
}
}
val safeFields = fold(emptyList<Field>()) { cur, next ->
cur.safeAddField(next, ensuredLocation)
}
check(safeFields.size == size) {
"Data lost!"
}
return safeFields
}
/**
* Safely adds a new [Field] to this collection while ensuring that it does not conflict with the
* existing field ids.
*
* @param newField the new [Field] to add.
* @param ensuredLocation the [Location] of the element holding this list to ensure fields match it.
* @receiver the source list to add this to. A defensive new copy will be made.
* @return the new fields list with the new field appended to the end.
*/
fun List<Field>.safeAddField(newField: Field, ensuredLocation: Location): List<Field> {
val defensiveCopy = newField.toBuilder()
.location(newField.location.matchTo(ensuredLocation))
.build()
if (none { it.id == newField.id }) {
return plus(defensiveCopy)
}
val finalField = map(Field::id).max()?.let { maxId ->
defensiveCopy.newId(maxId + 1)
} ?: defensiveCopy
return plus(finalField)
}
private fun Location.matchTo(source: Location): Location {
return if (base == source.base && path == source.path) {
this
} else {
Location.get(source.base, source.path)
}
}
/**
* Creates a new copy of this [Field] with the specified [newUUID] reflectively set via its internal
* [FieldElement] field.
*
* @param newUUID the new UUID to use. Defaults to a randomly generated one.
* @receiver the source [Field] to use. A defensive copy will be made.
* @return the new [Field] instance.
*/
fun <T : UserElement> T.newUuid(newUUID: UUID = UUID.randomUUID()): T {
if (this is UserType) {
UserType::class.java.getDeclaredField("mixin")
} else {
javaClass.getDeclaredField("mixin")
}
.apply {
isAccessible = true
val modifiersField = java.lang.reflect.Field::class.java
.getDeclaredField("modifiers")
modifiersField.isAccessible = true
modifiersField.setInt(this, modifiers and Modifier.FINAL.inv())
}
.get(this)
.let { mixin ->
// UserElementMixin
mixin.javaClass.getDeclaredField("uuid")
.apply {
isAccessible = true
val modifiersField = java.lang.reflect.Field::class.java
.getDeclaredField("modifiers")
modifiersField.isAccessible = true
modifiersField.setInt(this, modifiers and Modifier.FINAL.inv())
}
.apply {
val olduuid = uuid
set(mixin, newUUID)
check(olduuid != uuid) {
"New UUID setting failed!"
}
}
}
return this
}
/**
* Sets a new default value for a given [Field].
*
* @param const the new [ConstValueElement] to set
* @return this same [Field] instance.
*/
fun Field.setDefaultValue(const: ConstValueElement): Field {
val newElement = (elementField.get(this) as FieldElement).copy(constValue = const)
elementField.set(this, newElement)
return this
}
private val elementField = Field::class.java.getDeclaredField("element")
.apply {
isAccessible = true
val modifiersField = java.lang.reflect.Field::class.java
.getDeclaredField("modifiers")
modifiersField.isAccessible = true
modifiersField.setInt(this, modifiers and Modifier.FINAL.inv())
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No repository files or tests are named. Start by reviewing the public Field, FieldElement, UserElement, and UserType APIs referenced in the dump, then determine whether supported APIs should replace these reflection-based extensions; completion criteria are not defined in the issue.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kotlin
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 15/100